| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  os_android.cpp                                                        */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* 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.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | #include "os_android.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-10 17:35:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | #include "dir_access_jandroid.h"
 | 
					
						
							|  |  |  | #include "display_server_android.h"
 | 
					
						
							|  |  |  | #include "file_access_android.h"
 | 
					
						
							|  |  |  | #include "file_access_filesystem_jandroid.h"
 | 
					
						
							|  |  |  | #include "java_godot_io_wrapper.h"
 | 
					
						
							|  |  |  | #include "java_godot_wrapper.h"
 | 
					
						
							|  |  |  | #include "net_socket_android.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 19:33:38 -03:00
										 |  |  | #include "core/config/project_settings.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | #include "drivers/unix/dir_access_unix.h"
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #include "drivers/unix/file_access_unix.h"
 | 
					
						
							|  |  |  | #include "main/main.h"
 | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | #include "scene/main/scene_tree.h"
 | 
					
						
							| 
									
										
										
										
											2022-03-27 18:09:48 -07:00
										 |  |  | #include "servers/rendering_server.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-13 20:40:20 +07:00
										 |  |  | #include <dlfcn.h>
 | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | #include <sys/system_properties.h>
 | 
					
						
							| 
									
										
										
										
											2018-01-13 20:40:20 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | const char *OS_Android::ANDROID_EXEC_PATH = "apk"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 17:43:10 +01:00
										 |  |  | String _remove_symlink(const String &dir) { | 
					
						
							|  |  |  | 	// Workaround for Android 6.0+ using a symlink.
 | 
					
						
							|  |  |  | 	// Save the current directory.
 | 
					
						
							|  |  |  | 	char current_dir_name[2048]; | 
					
						
							|  |  |  | 	getcwd(current_dir_name, 2048); | 
					
						
							|  |  |  | 	// Change directory to the external data directory.
 | 
					
						
							|  |  |  | 	chdir(dir.utf8().get_data()); | 
					
						
							|  |  |  | 	// Get the actual directory without the potential symlink.
 | 
					
						
							|  |  |  | 	char dir_name_wihout_symlink[2048]; | 
					
						
							|  |  |  | 	getcwd(dir_name_wihout_symlink, 2048); | 
					
						
							|  |  |  | 	// Convert back to a String.
 | 
					
						
							|  |  |  | 	String dir_without_symlink(dir_name_wihout_symlink); | 
					
						
							|  |  |  | 	// Restore original current directory.
 | 
					
						
							|  |  |  | 	chdir(current_dir_name); | 
					
						
							|  |  |  | 	return dir_without_symlink; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-22 12:56:02 +07:00
										 |  |  | class AndroidLogger : public Logger { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	virtual void logv(const char *p_format, va_list p_list, bool p_err) { | 
					
						
							|  |  |  | 		__android_log_vprint(p_err ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "godot", p_format, p_list); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	virtual ~AndroidLogger() {} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 19:23:48 +03:00
										 |  |  | void OS_Android::alert(const String &p_alert, const String &p_title) { | 
					
						
							| 
									
										
										
										
											2022-05-30 22:13:49 +01:00
										 |  |  | 	ERR_FAIL_NULL(godot_java); | 
					
						
							| 
									
										
										
										
											2021-07-22 19:23:48 +03:00
										 |  |  | 	godot_java->alert(p_alert, p_title); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | void OS_Android::initialize_core() { | 
					
						
							|  |  |  | 	OS_Unix::initialize_core(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (use_apk_expansion) { | 
					
						
							| 
									
										
										
										
											2014-06-27 23:21:45 -03:00
										 |  |  | 		FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2015-09-03 23:24:55 -03:00
										 |  |  | 		FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | 	FileAccess::make_default<FileAccessFilesystemJAndroid>(FileAccess::ACCESS_FILESYSTEM); | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (use_apk_expansion) { | 
					
						
							| 
									
										
										
										
											2014-06-27 23:21:45 -03:00
										 |  |  | 		DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2014-06-27 23:21:45 -03:00
										 |  |  | 		DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_RESOURCES); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | 	DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_FILESYSTEM); | 
					
						
							| 
									
										
										
										
											2019-11-25 15:01:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	NetSocketAndroid::make_default(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | void OS_Android::initialize() { | 
					
						
							|  |  |  | 	initialize_core(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-07-20 08:37:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | void OS_Android::initialize_joypads() { | 
					
						
							| 
									
										
										
										
											2020-04-28 15:19:37 +02:00
										 |  |  | 	Input::get_singleton()->set_fallback_mapping(godot_java->get_input_fallback_mapping()); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 	// This queries/updates the currently connected devices/joypads.
 | 
					
						
							|  |  |  | 	godot_java->init_input_devices(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void OS_Android::set_main_loop(MainLoop *p_main_loop) { | 
					
						
							|  |  |  | 	main_loop = p_main_loop; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::delete_main_loop() { | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 	if (main_loop) { | 
					
						
							|  |  |  | 		memdelete(main_loop); | 
					
						
							|  |  |  | 		main_loop = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::finalize() { | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-21 00:17:24 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | OS_Android *OS_Android::get_singleton() { | 
					
						
							| 
									
										
										
										
											2022-04-07 13:23:40 +03:00
										 |  |  | 	return static_cast<OS_Android *>(OS::get_singleton()); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | GodotJavaWrapper *OS_Android::get_godot_java() { | 
					
						
							|  |  |  | 	return godot_java; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GodotIOJavaWrapper *OS_Android::get_godot_io_java() { | 
					
						
							|  |  |  | 	return godot_io_java; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-04 23:06:37 -03:00
										 |  |  | bool OS_Android::request_permission(const String &p_name) { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	return godot_java->request_permission(p_name); | 
					
						
							| 
									
										
										
										
											2019-03-04 23:06:37 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 21:17:44 +03:00
										 |  |  | bool OS_Android::request_permissions() { | 
					
						
							|  |  |  | 	return godot_java->request_permissions(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<String> OS_Android::get_granted_permissions() const { | 
					
						
							|  |  |  | 	return godot_java->get_granted_permissions(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-29 00:51:04 +02:00
										 |  |  | Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { | 
					
						
							| 
									
										
										
										
											2022-11-07 12:56:20 +02:00
										 |  |  | 	String path = p_path; | 
					
						
							|  |  |  | 	if (!FileAccess::exists(path)) { | 
					
						
							|  |  |  | 		path = p_path.get_file(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); | 
					
						
							| 
									
										
										
										
											2022-05-30 22:13:49 +01:00
										 |  |  | 	ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + "."); | 
					
						
							| 
									
										
										
										
											2022-04-29 00:51:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (r_resolved_path != nullptr) { | 
					
						
							| 
									
										
										
										
											2022-11-07 12:56:20 +02:00
										 |  |  | 		*r_resolved_path = path; | 
					
						
							| 
									
										
										
										
											2022-04-29 00:51:04 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-13 20:40:20 +07:00
										 |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 13:36:24 -04:00
										 |  |  | String OS_Android::get_name() const { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	return "Android"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | String OS_Android::get_system_property(const char *key) const { | 
					
						
							| 
									
										
										
										
											2023-05-27 18:21:23 +02:00
										 |  |  | 	String value; | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | 	char value_str[PROP_VALUE_MAX]; | 
					
						
							|  |  |  | 	if (__system_property_get(key, value_str)) { | 
					
						
							|  |  |  | 		value = String(value_str); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Android::get_distribution_name() const { | 
					
						
							|  |  |  | 	if (!get_system_property("ro.havoc.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Havoc OS"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("org.pex.version").is_empty()) { // Putting before "Pixel Experience", because it's derivating from it.
 | 
					
						
							|  |  |  | 		return "Pixel Extended"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("org.pixelexperience.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Pixel Experience"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.potato.version").is_empty()) { | 
					
						
							|  |  |  | 		return "POSP"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.xtended.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Project-Xtended"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("org.evolution.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Evolution X"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.corvus.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Corvus-Q"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.pa.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Paranoid Android"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.crdroid.version").is_empty()) { | 
					
						
							|  |  |  | 		return "crDroid Android"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.syberia.version").is_empty()) { | 
					
						
							|  |  |  | 		return "Syberia Project"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.arrow.version").is_empty()) { | 
					
						
							|  |  |  | 		return "ArrowOS"; | 
					
						
							|  |  |  | 	} else if (!get_system_property("ro.lineage.version").is_empty()) { // Putting LineageOS last, just in case any derivative writes to "ro.lineage.version".
 | 
					
						
							|  |  |  | 		return "LineageOS"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!get_system_property("ro.modversion").is_empty()) { // Handles other Android custom ROMs.
 | 
					
						
							|  |  |  | 		return vformat("%s %s", get_name(), "Custom ROM"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Handles stock Android.
 | 
					
						
							|  |  |  | 	return get_name(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Android::get_version() const { | 
					
						
							|  |  |  | 	const Vector<const char *> roms = { "ro.havoc.version", "org.pex.version", "org.pixelexperience.version", | 
					
						
							|  |  |  | 		"ro.potato.version", "ro.xtended.version", "org.evolution.version", "ro.corvus.version", "ro.pa.version", | 
					
						
							|  |  |  | 		"ro.crdroid.version", "ro.syberia.version", "ro.arrow.version", "ro.lineage.version" }; | 
					
						
							|  |  |  | 	for (int i = 0; i < roms.size(); i++) { | 
					
						
							| 
									
										
										
										
											2023-05-27 18:21:23 +02:00
										 |  |  | 		String rom_version = get_system_property(roms[i]); | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | 		if (!rom_version.is_empty()) { | 
					
						
							|  |  |  | 			return rom_version; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-27 18:21:23 +02:00
										 |  |  | 	String mod_version = get_system_property("ro.modversion"); // Handles other Android custom ROMs.
 | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | 	if (!mod_version.is_empty()) { | 
					
						
							|  |  |  | 		return mod_version; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Handles stock Android.
 | 
					
						
							| 
									
										
										
										
											2023-05-27 18:21:23 +02:00
										 |  |  | 	String sdk_version = get_system_property("ro.build.version.sdk_int"); | 
					
						
							|  |  |  | 	String build = get_system_property("ro.build.version.incremental"); | 
					
						
							| 
									
										
										
										
											2022-09-16 11:14:14 +02:00
										 |  |  | 	if (!sdk_version.is_empty()) { | 
					
						
							|  |  |  | 		if (!build.is_empty()) { | 
					
						
							|  |  |  | 			return vformat("%s.%s", sdk_version, build); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return sdk_version; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | MainLoop *OS_Android::get_main_loop() const { | 
					
						
							|  |  |  | 	return main_loop; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::main_loop_begin() { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (main_loop) { | 
					
						
							| 
									
										
										
										
											2020-12-22 09:50:29 +00:00
										 |  |  | 		main_loop->initialize(); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-21 12:07:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 18:09:48 -07:00
										 |  |  | bool OS_Android::main_loop_iterate(bool *r_should_swap_buffers) { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!main_loop) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-27 22:03:28 -08:00
										 |  |  | 	DisplayServerAndroid::get_singleton()->reset_swap_buffers_flag(); | 
					
						
							| 
									
										
										
										
											2020-10-08 02:37:58 +03:00
										 |  |  | 	DisplayServerAndroid::get_singleton()->process_events(); | 
					
						
							| 
									
										
										
										
											2022-04-25 00:03:00 -07:00
										 |  |  | 	uint64_t current_frames_drawn = Engine::get_singleton()->get_frames_drawn(); | 
					
						
							| 
									
										
										
										
											2022-03-27 18:09:48 -07:00
										 |  |  | 	bool exit = Main::iteration(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (r_should_swap_buffers) { | 
					
						
							| 
									
										
										
										
											2022-11-27 22:03:28 -08:00
										 |  |  | 		*r_should_swap_buffers = !is_in_low_processor_usage_mode() || | 
					
						
							|  |  |  | 				DisplayServerAndroid::get_singleton()->should_swap_buffers() || | 
					
						
							|  |  |  | 				RenderingServer::get_singleton()->has_changed() || | 
					
						
							|  |  |  | 				current_frames_drawn != Engine::get_singleton()->get_frames_drawn(); | 
					
						
							| 
									
										
										
										
											2022-03-27 18:09:48 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return exit; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::main_loop_end() { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (main_loop) { | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | 		SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); | 
					
						
							|  |  |  | 		if (scene_tree) { | 
					
						
							|  |  |  | 			scene_tree->quit(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-12-22 09:50:29 +00:00
										 |  |  | 		main_loop->finalize(); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::main_loop_focusout() { | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 	DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	audio_driver_android.set_pause(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void OS_Android::main_loop_focusin() { | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 	DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	audio_driver_android.set_pause(false); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error OS_Android::shell_open(String p_uri) { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	return godot_io_java->open_uri(p_uri); | 
					
						
							| 
									
										
										
										
											2016-07-21 12:07:01 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | String OS_Android::get_resource_dir() const { | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	return OS_Unix::get_resource_dir(); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2023-04-28 13:15:36 +02:00
										 |  |  | 	if (remote_fs_dir.is_empty()) { | 
					
						
							|  |  |  | 		return "/"; // Android has its own filesystem for resources inside the APK
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return remote_fs_dir; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Android::get_locale() const { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	String locale = godot_io_java->get_locale(); | 
					
						
							| 
									
										
										
										
											2021-12-09 03:42:46 -06:00
										 |  |  | 	if (!locale.is_empty()) { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 		return locale; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	return OS_Unix::get_locale(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Android::get_model_name() const { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	String model = godot_io_java->get_model(); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!model.is_empty()) { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 		return model; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return OS_Unix::get_model_name(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | String OS_Android::get_data_path() const { | 
					
						
							|  |  |  | 	return get_user_data_dir(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | void OS_Android::_load_system_font_config() { | 
					
						
							|  |  |  | 	font_aliases.clear(); | 
					
						
							|  |  |  | 	fonts.clear(); | 
					
						
							|  |  |  | 	font_names.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Ref<XMLParser> parser; | 
					
						
							|  |  |  | 	parser.instantiate(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Error err = parser->open(String(getenv("ANDROID_ROOT")).path_join("/etc/fonts.xml")); | 
					
						
							|  |  |  | 	if (err == OK) { | 
					
						
							|  |  |  | 		bool in_font_node = false; | 
					
						
							|  |  |  | 		String fb, fn; | 
					
						
							|  |  |  | 		FontInfo fi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		while (parser->read() == OK) { | 
					
						
							|  |  |  | 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { | 
					
						
							|  |  |  | 				in_font_node = false; | 
					
						
							|  |  |  | 				if (parser->get_node_name() == "familyset") { | 
					
						
							| 
									
										
										
										
											2022-11-28 11:00:48 +02:00
										 |  |  | 					int ver = parser->has_attribute("version") ? parser->get_named_attribute_value("version").to_int() : 0; | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 					if (ver < 21) { | 
					
						
							|  |  |  | 						ERR_PRINT(vformat("Unsupported font config version %s", ver)); | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else if (parser->get_node_name() == "alias") { | 
					
						
							| 
									
										
										
										
											2022-11-28 11:00:48 +02:00
										 |  |  | 					String name = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String(); | 
					
						
							|  |  |  | 					String to = parser->has_attribute("to") ? parser->get_named_attribute_value("to").strip_edges() : String(); | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 					if (!name.is_empty() && !to.is_empty()) { | 
					
						
							|  |  |  | 						font_aliases[name] = to; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else if (parser->get_node_name() == "family") { | 
					
						
							| 
									
										
										
										
											2022-11-28 11:00:48 +02:00
										 |  |  | 					fn = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String(); | 
					
						
							|  |  |  | 					String lang_code = parser->has_attribute("lang") ? parser->get_named_attribute_value("lang").strip_edges() : String(); | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 					Vector<String> lang_codes = lang_code.split(","); | 
					
						
							|  |  |  | 					for (int i = 0; i < lang_codes.size(); i++) { | 
					
						
							|  |  |  | 						Vector<String> lang_code_elements = lang_codes[i].split("-"); | 
					
						
							|  |  |  | 						if (lang_code_elements.size() >= 1 && lang_code_elements[0] != "und") { | 
					
						
							|  |  |  | 							// Add missing script codes.
 | 
					
						
							|  |  |  | 							if (lang_code_elements[0] == "ko") { | 
					
						
							|  |  |  | 								fi.script.insert("Hani"); | 
					
						
							|  |  |  | 								fi.script.insert("Hang"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (lang_code_elements[0] == "ja") { | 
					
						
							|  |  |  | 								fi.script.insert("Hani"); | 
					
						
							|  |  |  | 								fi.script.insert("Kana"); | 
					
						
							|  |  |  | 								fi.script.insert("Hira"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (!lang_code_elements[0].is_empty()) { | 
					
						
							|  |  |  | 								fi.lang.insert(lang_code_elements[0]); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (lang_code_elements.size() >= 2) { | 
					
						
							|  |  |  | 							// Add common codes for variants and remove variants not supported by HarfBuzz/ICU.
 | 
					
						
							|  |  |  | 							if (lang_code_elements[1] == "Aran") { | 
					
						
							|  |  |  | 								fi.script.insert("Arab"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (lang_code_elements[1] == "Cyrs") { | 
					
						
							|  |  |  | 								fi.script.insert("Cyrl"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (lang_code_elements[1] == "Hanb") { | 
					
						
							|  |  |  | 								fi.script.insert("Hani"); | 
					
						
							|  |  |  | 								fi.script.insert("Bopo"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (lang_code_elements[1] == "Hans" || lang_code_elements[1] == "Hant") { | 
					
						
							|  |  |  | 								fi.script.insert("Hani"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (lang_code_elements[1] == "Syrj" || lang_code_elements[1] == "Syre" || lang_code_elements[1] == "Syrn") { | 
					
						
							|  |  |  | 								fi.script.insert("Syrc"); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (!lang_code_elements[1].is_empty() && lang_code_elements[1] != "Zsym" && lang_code_elements[1] != "Zsye" && lang_code_elements[1] != "Zmth") { | 
					
						
							|  |  |  | 								fi.script.insert(lang_code_elements[1]); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else if (parser->get_node_name() == "font") { | 
					
						
							|  |  |  | 					in_font_node = true; | 
					
						
							| 
									
										
										
										
											2022-11-28 11:00:48 +02:00
										 |  |  | 					fb = parser->has_attribute("fallbackFor") ? parser->get_named_attribute_value("fallbackFor").strip_edges() : String(); | 
					
						
							|  |  |  | 					fi.weight = parser->has_attribute("weight") ? parser->get_named_attribute_value("weight").to_int() : 400; | 
					
						
							|  |  |  | 					fi.italic = parser->has_attribute("style") && parser->get_named_attribute_value("style").strip_edges() == "italic"; | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (parser->get_node_type() == XMLParser::NODE_TEXT) { | 
					
						
							|  |  |  | 				if (in_font_node) { | 
					
						
							|  |  |  | 					fi.filename = parser->get_node_data().strip_edges(); | 
					
						
							|  |  |  | 					fi.font_name = fn; | 
					
						
							|  |  |  | 					if (!fb.is_empty() && fn.is_empty()) { | 
					
						
							|  |  |  | 						fi.font_name = fb; | 
					
						
							|  |  |  | 						fi.priority = 2; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (fi.font_name.is_empty()) { | 
					
						
							|  |  |  | 						fi.font_name = "sans-serif"; | 
					
						
							|  |  |  | 						fi.priority = 5; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (fi.font_name.ends_with("-condensed")) { | 
					
						
							|  |  |  | 						fi.stretch = 75; | 
					
						
							|  |  |  | 						fi.font_name = fi.font_name.trim_suffix("-condensed"); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					fonts.push_back(fi); | 
					
						
							|  |  |  | 					font_names.insert(fi.font_name); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { | 
					
						
							|  |  |  | 				in_font_node = false; | 
					
						
							|  |  |  | 				if (parser->get_node_name() == "font") { | 
					
						
							|  |  |  | 					fb = String(); | 
					
						
							|  |  |  | 					fi.font_name = String(); | 
					
						
							|  |  |  | 					fi.priority = 0; | 
					
						
							|  |  |  | 					fi.weight = 400; | 
					
						
							|  |  |  | 					fi.stretch = 100; | 
					
						
							|  |  |  | 					fi.italic = false; | 
					
						
							|  |  |  | 				} else if (parser->get_node_name() == "family") { | 
					
						
							|  |  |  | 					fi = FontInfo(); | 
					
						
							|  |  |  | 					fn = String(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		parser->close(); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ERR_PRINT("Unable to load font config"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	font_config_loaded = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<String> OS_Android::get_system_fonts() const { | 
					
						
							|  |  |  | 	if (!font_config_loaded) { | 
					
						
							|  |  |  | 		const_cast<OS_Android *>(this)->_load_system_font_config(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	Vector<String> ret; | 
					
						
							|  |  |  | 	for (const String &E : font_names) { | 
					
						
							|  |  |  | 		ret.push_back(E); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<String> OS_Android::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const { | 
					
						
							|  |  |  | 	if (!font_config_loaded) { | 
					
						
							|  |  |  | 		const_cast<OS_Android *>(this)->_load_system_font_config(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	String font_name = p_font_name.to_lower(); | 
					
						
							|  |  |  | 	if (font_aliases.has(font_name)) { | 
					
						
							|  |  |  | 		font_name = font_aliases[font_name]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	String root = String(getenv("ANDROID_ROOT")).path_join("fonts"); | 
					
						
							|  |  |  | 	String lang_prefix = p_locale.split("_")[0]; | 
					
						
							|  |  |  | 	Vector<String> ret; | 
					
						
							|  |  |  | 	int best_score = 0; | 
					
						
							|  |  |  | 	for (const List<FontInfo>::Element *E = fonts.front(); E; E = E->next()) { | 
					
						
							|  |  |  | 		int score = 0; | 
					
						
							|  |  |  | 		if (!E->get().script.is_empty() && !p_script.is_empty() && !E->get().script.has(p_script)) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		float sim = E->get().font_name.similarity(font_name); | 
					
						
							|  |  |  | 		if (sim > 0.0) { | 
					
						
							|  |  |  | 			score += (60 * sim + 5 - E->get().priority); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (E->get().lang.has(p_locale)) { | 
					
						
							|  |  |  | 			score += 120; | 
					
						
							|  |  |  | 		} else if (E->get().lang.has(lang_prefix)) { | 
					
						
							|  |  |  | 			score += 115; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (E->get().script.has(p_script)) { | 
					
						
							|  |  |  | 			score += 240; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		score += (20 - Math::abs(E->get().weight - p_weight) / 50); | 
					
						
							|  |  |  | 		score += (20 - Math::abs(E->get().stretch - p_stretch) / 10); | 
					
						
							|  |  |  | 		if (E->get().italic == p_italic) { | 
					
						
							|  |  |  | 			score += 30; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (score > best_score) { | 
					
						
							|  |  |  | 			best_score = score; | 
					
						
							|  |  |  | 			if (ret.find(root.path_join(E->get().filename)) < 0) { | 
					
						
							|  |  |  | 				ret.insert(0, root.path_join(E->get().filename)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else if (score == best_score || E->get().script.is_empty()) { | 
					
						
							|  |  |  | 			if (ret.find(root.path_join(E->get().filename)) < 0) { | 
					
						
							|  |  |  | 				ret.push_back(root.path_join(E->get().filename)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (score >= 490) { | 
					
						
							|  |  |  | 			break; // Perfect match.
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String OS_Android::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const { | 
					
						
							|  |  |  | 	if (!font_config_loaded) { | 
					
						
							|  |  |  | 		const_cast<OS_Android *>(this)->_load_system_font_config(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	String font_name = p_font_name.to_lower(); | 
					
						
							|  |  |  | 	if (font_aliases.has(font_name)) { | 
					
						
							|  |  |  | 		font_name = font_aliases[font_name]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	String root = String(getenv("ANDROID_ROOT")).path_join("fonts"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int best_score = 0; | 
					
						
							|  |  |  | 	const List<FontInfo>::Element *best_match = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (const List<FontInfo>::Element *E = fonts.front(); E; E = E->next()) { | 
					
						
							|  |  |  | 		int score = 0; | 
					
						
							|  |  |  | 		if (E->get().font_name == font_name) { | 
					
						
							|  |  |  | 			score += (65 - E->get().priority); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		score += (20 - Math::abs(E->get().weight - p_weight) / 50); | 
					
						
							|  |  |  | 		score += (20 - Math::abs(E->get().stretch - p_stretch) / 10); | 
					
						
							|  |  |  | 		if (E->get().italic == p_italic) { | 
					
						
							|  |  |  | 			score += 30; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (score >= 60 && score > best_score) { | 
					
						
							|  |  |  | 			best_score = score; | 
					
						
							|  |  |  | 			best_match = E; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (score >= 140) { | 
					
						
							|  |  |  | 			break; // Perfect match.
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (best_match) { | 
					
						
							|  |  |  | 		return root.path_join(best_match->get().filename); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return String(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | String OS_Android::get_executable_path() const { | 
					
						
							|  |  |  | 	// Since unix process creation is restricted on Android, we bypass
 | 
					
						
							|  |  |  | 	// OS_Unix::get_executable_path() so we can return ANDROID_EXEC_PATH.
 | 
					
						
							|  |  |  | 	// Detection of ANDROID_EXEC_PATH allows to handle process creation in an Android compliant
 | 
					
						
							|  |  |  | 	// manner.
 | 
					
						
							|  |  |  | 	return OS::get_executable_path(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 15:25:22 +01:00
										 |  |  | String OS_Android::get_user_data_dir() const { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!data_dir_cache.is_empty()) { | 
					
						
							| 
									
										
										
										
											2016-07-02 11:48:02 -03:00
										 |  |  | 		return data_dir_cache; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-02 11:48:02 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	String data_dir = godot_io_java->get_user_data_dir(); | 
					
						
							| 
									
										
										
										
											2021-12-09 03:42:46 -06:00
										 |  |  | 	if (!data_dir.is_empty()) { | 
					
						
							| 
									
										
										
										
											2021-06-08 17:43:10 +01:00
										 |  |  | 		data_dir_cache = _remove_symlink(data_dir); | 
					
						
							| 
									
										
										
										
											2016-07-02 16:04:00 -03:00
										 |  |  | 		return data_dir_cache; | 
					
						
							| 
									
										
										
										
											2016-07-02 11:48:02 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-08 17:43:10 +01:00
										 |  |  | 	return "."; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-02 11:48:02 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | String OS_Android::get_cache_path() const { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!cache_dir_cache.is_empty()) { | 
					
						
							| 
									
										
										
										
											2021-02-22 22:54:12 +01:00
										 |  |  | 		return cache_dir_cache; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-22 22:54:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | 	String cache_dir = godot_io_java->get_cache_dir(); | 
					
						
							| 
									
										
										
										
											2021-12-09 03:42:46 -06:00
										 |  |  | 	if (!cache_dir.is_empty()) { | 
					
						
							| 
									
										
										
										
											2021-02-22 22:54:12 +01:00
										 |  |  | 		cache_dir_cache = _remove_symlink(cache_dir); | 
					
						
							|  |  |  | 		return cache_dir_cache; | 
					
						
							| 
									
										
										
										
											2021-06-08 17:43:10 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	return "."; | 
					
						
							| 
									
										
										
										
											2016-07-21 12:07:01 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 17:17:31 +07:00
										 |  |  | String OS_Android::get_unique_id() const { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	String unique_id = godot_io_java->get_unique_id(); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!unique_id.is_empty()) { | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 		return unique_id; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-07 17:17:31 +07:00
										 |  |  | 	return OS::get_unique_id(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | String OS_Android::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { | 
					
						
							|  |  |  | 	return godot_io_java->get_system_dir(p_dir, p_shared_storage); | 
					
						
							| 
									
										
										
										
											2014-12-02 14:02:41 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 18:39:31 -07:00
										 |  |  | Error OS_Android::move_to_trash(const String &p_path) { | 
					
						
							|  |  |  | 	Ref<DirAccess> da_ref = DirAccess::create_for_path(p_path); | 
					
						
							|  |  |  | 	if (da_ref.is_null()) { | 
					
						
							|  |  |  | 		return FAILED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if it's a directory
 | 
					
						
							|  |  |  | 	if (da_ref->dir_exists(p_path)) { | 
					
						
							|  |  |  | 		Error err = da_ref->change_dir(p_path); | 
					
						
							|  |  |  | 		if (err) { | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// This is directory, let's erase its contents
 | 
					
						
							|  |  |  | 		err = da_ref->erase_contents_recursive(); | 
					
						
							|  |  |  | 		if (err) { | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Remove the top directory
 | 
					
						
							|  |  |  | 		return da_ref->remove(p_path); | 
					
						
							|  |  |  | 	} else if (da_ref->file_exists(p_path)) { | 
					
						
							|  |  |  | 		// This is a file, let's remove it.
 | 
					
						
							|  |  |  | 		return da_ref->remove(p_path); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return FAILED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | void OS_Android::set_display_size(const Size2i &p_size) { | 
					
						
							|  |  |  | 	display_size = p_size; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | Size2i OS_Android::get_display_size() const { | 
					
						
							|  |  |  | 	return display_size; | 
					
						
							| 
									
										
										
										
											2014-03-13 22:57:24 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { | 
					
						
							| 
									
										
										
										
											2021-10-26 08:18:39 -07:00
										 |  |  | #if defined(GLES3_ENABLED)
 | 
					
						
							| 
									
										
										
										
											2022-05-30 22:13:49 +01:00
										 |  |  | 	ERR_FAIL_NULL(p_gl_extensions); | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 	gl_extensions = p_gl_extensions; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-12-02 11:15:48 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 19:00:28 +01:00
										 |  |  | void OS_Android::set_native_window(ANativeWindow *p_native_window) { | 
					
						
							|  |  |  | #if defined(VULKAN_ENABLED)
 | 
					
						
							|  |  |  | 	native_window = p_native_window; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | ANativeWindow *OS_Android::get_native_window() const { | 
					
						
							|  |  |  | #if defined(VULKAN_ENABLED)
 | 
					
						
							|  |  |  | 	return native_window; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	return nullptr; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-01-24 05:11:59 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-18 00:27:29 +09:00
										 |  |  | void OS_Android::vibrate_handheld(int p_duration_ms) { | 
					
						
							|  |  |  | 	godot_java->vibrate(p_duration_ms); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | String OS_Android::get_config_path() const { | 
					
						
							| 
									
										
										
										
											2022-08-29 19:34:01 -05:00
										 |  |  | 	return get_user_data_dir().path_join("config"); | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 11:24:12 -08:00
										 |  |  | void OS_Android::benchmark_begin_measure(const String &p_what) { | 
					
						
							|  |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	godot_java->begin_benchmark_measure(p_what); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::benchmark_end_measure(const String &p_what) { | 
					
						
							|  |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	godot_java->end_benchmark_measure(p_what); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OS_Android::benchmark_dump() { | 
					
						
							|  |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 	if (!is_use_benchmark_set()) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	godot_java->dump_benchmark(get_benchmark_file()); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 17:00:46 -03:00
										 |  |  | bool OS_Android::_check_internal_feature_support(const String &p_feature) { | 
					
						
							| 
									
										
										
										
											2022-11-21 15:04:01 +02:00
										 |  |  | 	if (p_feature == "system_fonts") { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-26 11:58:47 -03:00
										 |  |  | 	if (p_feature == "mobile") { | 
					
						
							| 
									
										
										
										
											2017-10-02 22:01:43 +07:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #if defined(__aarch64__)
 | 
					
						
							| 
									
										
										
										
											2021-12-15 17:38:10 -08:00
										 |  |  | 	if (p_feature == "arm64-v8a" || p_feature == "arm64") { | 
					
						
							| 
									
										
										
										
											2017-10-02 22:01:43 +07:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #elif defined(__ARM_ARCH_7A__)
 | 
					
						
							| 
									
										
										
										
											2021-12-15 17:38:10 -08:00
										 |  |  | 	if (p_feature == "armeabi-v7a" || p_feature == "armeabi" || p_feature == "arm32") { | 
					
						
							| 
									
										
										
										
											2017-10-02 22:01:43 +07:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #elif defined(__arm__)
 | 
					
						
							| 
									
										
										
										
											2021-12-15 17:38:10 -08:00
										 |  |  | 	if (p_feature == "armeabi" || p_feature == "arm") { | 
					
						
							| 
									
										
										
										
											2017-10-02 22:01:43 +07:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2017-07-19 17:00:46 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion) { | 
					
						
							| 
									
										
										
										
											2023-01-21 22:04:44 -08:00
										 |  |  | 	display_size.width = DEFAULT_WINDOW_WIDTH; | 
					
						
							|  |  |  | 	display_size.height = DEFAULT_WINDOW_HEIGHT; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	use_apk_expansion = p_use_apk_expansion; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	main_loop = nullptr; | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-26 08:18:39 -07:00
										 |  |  | #if defined(GLES3_ENABLED)
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	gl_extensions = nullptr; | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 19:00:28 +01:00
										 |  |  | #if defined(VULKAN_ENABLED)
 | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 	native_window = nullptr; | 
					
						
							| 
									
										
										
										
											2020-03-05 19:00:28 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-13 23:51:55 +11:00
										 |  |  | 	godot_java = p_godot_java; | 
					
						
							|  |  |  | 	godot_io_java = p_godot_io_java; | 
					
						
							| 
									
										
										
										
											2017-09-22 12:56:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-21 16:35:01 +07:00
										 |  |  | 	Vector<Logger *> loggers; | 
					
						
							|  |  |  | 	loggers.push_back(memnew(AndroidLogger)); | 
					
						
							|  |  |  | 	_set_logger(memnew(CompositeLogger(loggers))); | 
					
						
							| 
									
										
										
										
											2018-03-04 14:18:05 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AudioDriverManager::add_driver(&audio_driver_android); | 
					
						
							| 
									
										
										
										
											2020-03-27 17:30:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	DisplayServerAndroid::register_android_driver(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | Error OS_Android::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { | 
					
						
							|  |  |  | 	if (p_path == ANDROID_EXEC_PATH) { | 
					
						
							|  |  |  | 		return create_instance(p_arguments); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return OS_Unix::execute(p_path, p_arguments, r_pipe, r_exitcode, read_stderr, p_pipe_mutex, p_open_console); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error OS_Android::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { | 
					
						
							|  |  |  | 	if (p_path == ANDROID_EXEC_PATH) { | 
					
						
							|  |  |  | 		return create_instance(p_arguments, r_child_id); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error OS_Android::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { | 
					
						
							| 
									
										
										
										
											2023-01-26 02:55:47 -08:00
										 |  |  | 	int instance_id = godot_java->create_new_godot_instance(p_arguments); | 
					
						
							|  |  |  | 	if (r_child_id) { | 
					
						
							|  |  |  | 		*r_child_id = instance_id; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-25 16:45:16 +03:00
										 |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-26 02:55:47 -08:00
										 |  |  | Error OS_Android::kill(const ProcessID &p_pid) { | 
					
						
							|  |  |  | 	if (godot_java->force_quit(nullptr, p_pid)) { | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return OS_Unix::kill(p_pid); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 21:17:55 +02:00
										 |  |  | String OS_Android::get_system_ca_certificates() { | 
					
						
							|  |  |  | 	return godot_java->get_ca_certificates(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-28 13:15:36 +02:00
										 |  |  | Error OS_Android::setup_remote_filesystem(const String &p_server_host, int p_port, const String &p_password, String &r_project_path) { | 
					
						
							|  |  |  | 	r_project_path = get_user_data_dir(); | 
					
						
							|  |  |  | 	Error err = OS_Unix::setup_remote_filesystem(p_server_host, p_port, p_password, r_project_path); | 
					
						
							|  |  |  | 	if (err == OK) { | 
					
						
							|  |  |  | 		remote_fs_dir = r_project_path; | 
					
						
							|  |  |  | 		FileAccess::make_default<FileAccessFilesystemJAndroid>(FileAccess::ACCESS_RESOURCES); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | OS_Android::~OS_Android() { | 
					
						
							|  |  |  | } |