summaryrefslogtreecommitdiffstats
path: root/platform/android
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android')
-rw-r--r--platform/android/SCsub2
-rw-r--r--platform/android/android_input_handler.cpp4
-rw-r--r--platform/android/detect.py9
-rw-r--r--platform/android/dir_access_jandroid.cpp2
-rw-r--r--platform/android/dir_access_jandroid.h2
-rw-r--r--platform/android/display_server_android.cpp89
-rw-r--r--platform/android/display_server_android.h9
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml21
-rw-r--r--platform/android/export/export_plugin.cpp140
-rw-r--r--platform/android/export/export_plugin.h11
-rw-r--r--platform/android/export/gradle_export_util.cpp8
-rw-r--r--platform/android/export/gradle_export_util.h3
-rw-r--r--platform/android/java/app/build.gradle8
-rw-r--r--platform/android/java/app/config.gradle23
-rw-r--r--platform/android/java/app/gradle.properties3
-rw-r--r--platform/android/java/gradle.properties3
-rw-r--r--platform/android/java/lib/build.gradle3
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.kt26
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java8
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java16
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java30
-rw-r--r--platform/android/java_godot_lib_jni.cpp7
-rw-r--r--platform/android/java_godot_lib_jni.h1
-rw-r--r--platform/android/net_socket_android.cpp4
-rw-r--r--platform/android/net_socket_android.h4
-rw-r--r--platform/android/os_android.cpp10
-rw-r--r--platform/android/os_android.h4
-rw-r--r--platform/android/rendering_context_driver_vulkan_android.cpp (renamed from platform/android/vulkan_context_android.cpp)36
-rw-r--r--platform/android/rendering_context_driver_vulkan_android.h (renamed from platform/android/vulkan_context_android.h)25
30 files changed, 366 insertions, 150 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 97262cf148..31bc7c25b0 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -23,7 +23,7 @@ android_files = [
"android_keys_utils.cpp",
"display_server_android.cpp",
"plugin/godot_plugin_jni.cpp",
- "vulkan_context_android.cpp",
+ "rendering_context_driver_vulkan_android.cpp",
]
env_android = env.Clone()
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 8e7f355114..373dd399e4 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -207,6 +207,7 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const
ev->set_index(touch[i].id);
ev->set_position(p_points[idx].pos);
ev->set_relative(p_points[idx].pos - touch[i].pos);
+ ev->set_relative_screen_position(ev->get_relative());
Input::get_singleton()->parse_input_event(ev);
touch.write[i].pos = p_points[idx].pos;
}
@@ -306,6 +307,7 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an
ev->set_position(p_event_pos);
ev->set_global_position(p_event_pos);
ev->set_relative(p_event_pos - hover_prev_pos);
+ ev->set_relative_screen_position(ev->get_relative());
Input::get_singleton()->parse_input_event(ev);
hover_prev_pos = p_event_pos;
} break;
@@ -342,10 +344,12 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an
ev->set_position(hover_prev_pos);
ev->set_global_position(hover_prev_pos);
ev->set_relative(p_event_pos);
+ ev->set_relative_screen_position(p_event_pos);
} else {
ev->set_position(p_event_pos);
ev->set_global_position(p_event_pos);
ev->set_relative(p_event_pos - hover_prev_pos);
+ ev->set_relative_screen_position(ev->get_relative());
mouse_event_info.pos = p_event_pos;
hover_prev_pos = p_event_pos;
}
diff --git a/platform/android/detect.py b/platform/android/detect.py
index b396e5eb2d..98b3ecdeff 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -6,7 +6,7 @@ import subprocess
from typing import TYPE_CHECKING
if TYPE_CHECKING:
- from SCons import Environment
+ from SCons.Script.SConscript import SConsEnvironment
def get_name():
@@ -28,6 +28,7 @@ def get_opts():
"android-" + str(get_min_target_api()),
),
BoolVariable("store_release", "Editor build for Google Play Store (for official builds only)", False),
+ BoolVariable("generate_apk", "Generate an APK/AAB after building Android library by calling Gradle", False),
]
@@ -50,7 +51,7 @@ def get_min_sdk_version(platform):
return int(platform.split("-")[1])
-def get_android_ndk_root(env):
+def get_android_ndk_root(env: "SConsEnvironment"):
return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
@@ -73,7 +74,7 @@ def get_flags():
# Check if Android NDK version is installed
# If not, install it.
-def install_ndk_if_needed(env):
+def install_ndk_if_needed(env: "SConsEnvironment"):
print("Checking for Android NDK...")
sdk_root = env["ANDROID_HOME"]
if not os.path.exists(get_android_ndk_root(env)):
@@ -95,7 +96,7 @@ def install_ndk_if_needed(env):
env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env)
-def configure(env: "Environment"):
+def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
if env["arch"] not in supported_arches:
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index d24d3fa389..972a7dbe6a 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -218,7 +218,7 @@ bool DirAccessJAndroid::dir_exists(String p_dir) {
}
}
-Error DirAccessJAndroid::make_dir_recursive(String p_dir) {
+Error DirAccessJAndroid::make_dir_recursive(const String &p_dir) {
// Check if the directory exists already
if (dir_exists(p_dir)) {
return ERR_ALREADY_EXISTS;
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index 5ee4c85659..9aaa78f38c 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -77,7 +77,7 @@ public:
virtual bool dir_exists(String p_dir) override;
virtual Error make_dir(String p_dir) override;
- virtual Error make_dir_recursive(String p_dir) override;
+ virtual Error make_dir_recursive(const String &p_dir) override;
virtual Error rename(String p_from, String p_to) override;
virtual Error remove(String p_name) override;
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 340823baac..01ecbc7164 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -42,7 +42,7 @@
#include "servers/rendering/rendering_device.h"
#if defined(VULKAN_ENABLED)
-#include "vulkan_context_android.h"
+#include "rendering_context_driver_vulkan_android.h"
#endif
#endif
@@ -127,6 +127,16 @@ bool DisplayServerAndroid::is_dark_mode() const {
return godot_java->is_dark_mode();
}
+void DisplayServerAndroid::set_system_theme_change_callback(const Callable &p_callable) {
+ system_theme_changed = p_callable;
+}
+
+void DisplayServerAndroid::emit_system_theme_changed() {
+ if (system_theme_changed.is_valid()) {
+ system_theme_changed.call_deferred();
+ }
+}
+
void DisplayServerAndroid::clipboard_set(const String &p_text) {
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
ERR_FAIL_NULL(godot_java);
@@ -518,15 +528,17 @@ void DisplayServerAndroid::register_android_driver() {
void DisplayServerAndroid::reset_window() {
#if defined(RD_ENABLED)
- if (context_rd) {
- VSyncMode last_vsync_mode = context_rd->get_vsync_mode(MAIN_WINDOW_ID);
- context_rd->window_destroy(MAIN_WINDOW_ID);
+ if (rendering_context) {
+ if (rendering_device) {
+ rendering_device->screen_free(MAIN_WINDOW_ID);
+ }
- Size2i display_size = OS_Android::get_singleton()->get_display_size();
+ VSyncMode last_vsync_mode = rendering_context->window_get_vsync_mode(MAIN_WINDOW_ID);
+ rendering_context->window_destroy(MAIN_WINDOW_ID);
union {
#ifdef VULKAN_ENABLED
- VulkanContextAndroid::WindowPlatformData vulkan;
+ RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan;
#endif
} wpd;
#ifdef VULKAN_ENABLED
@@ -537,10 +549,19 @@ void DisplayServerAndroid::reset_window() {
}
#endif
- if (context_rd->window_create(MAIN_WINDOW_ID, last_vsync_mode, display_size.width, display_size.height, &wpd) != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
- ERR_FAIL_MSG(vformat("Failed to reset %s window.", context_rd->get_api_name()));
+ if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
+ ERR_PRINT(vformat("Failed to reset %s window.", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
+ return;
+ }
+
+ Size2i display_size = OS_Android::get_singleton()->get_display_size();
+ rendering_context->window_set_size(MAIN_WINDOW_ID, display_size.width, display_size.height);
+ rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, last_vsync_mode);
+
+ if (rendering_device) {
+ rendering_device->screen_create(MAIN_WINDOW_ID);
}
}
#endif
@@ -564,27 +585,26 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
#endif
#if defined(RD_ENABLED)
- context_rd = nullptr;
+ rendering_context = nullptr;
rendering_device = nullptr;
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
- context_rd = memnew(VulkanContextAndroid);
+ rendering_context = memnew(RenderingContextDriverVulkanAndroid);
}
#endif
- if (context_rd) {
- if (context_rd->initialize() != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
- ERR_FAIL_MSG(vformat("Failed to initialize %s context", context_rd->get_api_name()));
+ if (rendering_context) {
+ if (rendering_context->initialize() != OK) {
+ ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
+ return;
}
- Size2i display_size = OS_Android::get_singleton()->get_display_size();
-
union {
#ifdef VULKAN_ENABLED
- VulkanContextAndroid::WindowPlatformData vulkan;
+ RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan;
#endif
} wpd;
#ifdef VULKAN_ENABLED
@@ -595,14 +615,20 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
}
#endif
- if (context_rd->window_create(MAIN_WINDOW_ID, p_vsync_mode, display_size.width, display_size.height, &wpd) != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
- ERR_FAIL_MSG(vformat("Failed to create %s window.", context_rd->get_api_name()));
+ if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
+ ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
+ return;
}
+ Size2i display_size = OS_Android::get_singleton()->get_display_size();
+ rendering_context->window_set_size(MAIN_WINDOW_ID, display_size.width, display_size.height);
+ rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode);
+
rendering_device = memnew(RenderingDevice);
- rendering_device->initialize(context_rd);
+ rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+ rendering_device->screen_create(MAIN_WINDOW_ID);
RendererCompositorRD::make_current();
}
@@ -617,11 +643,10 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
DisplayServerAndroid::~DisplayServerAndroid() {
#if defined(RD_ENABLED)
if (rendering_device) {
- rendering_device->finalize();
memdelete(rendering_device);
}
- if (context_rd) {
- memdelete(context_rd);
+ if (rendering_context) {
+ memdelete(rendering_context);
}
#endif
}
@@ -713,16 +738,16 @@ void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor
void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->set_vsync_mode(p_window, p_vsync_mode);
+ if (rendering_context) {
+ rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
}
#endif
}
DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_window) const {
#if defined(RD_ENABLED)
- if (context_rd) {
- return context_rd->get_vsync_mode(p_window);
+ if (rendering_context) {
+ return rendering_context->window_get_vsync_mode(p_window);
}
#endif
return DisplayServer::VSYNC_ENABLED;
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 80af4f00c1..c95eaddf93 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -34,7 +34,7 @@
#include "servers/display_server.h"
#if defined(RD_ENABLED)
-class ApiContextRD;
+class RenderingContextDriver;
class RenderingDevice;
#endif
@@ -73,7 +73,7 @@ class DisplayServerAndroid : public DisplayServer {
CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
#if defined(RD_ENABLED)
- ApiContextRD *context_rd = nullptr;
+ RenderingContextDriver *rendering_context = nullptr;
RenderingDevice *rendering_device = nullptr;
#endif
@@ -84,6 +84,8 @@ class DisplayServerAndroid : public DisplayServer {
Callable input_text_callback;
Callable rect_changed_callback;
+ Callable system_theme_changed;
+
void _window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred = false) const;
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
@@ -103,8 +105,11 @@ public:
virtual void tts_resume() override;
virtual void tts_stop() override;
+ void emit_system_theme_changed();
+
virtual bool is_dark_mode_supported() const override;
virtual bool is_dark_mode() const override;
+ virtual void set_system_theme_change_callback(const Callable &p_callable) override;
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index dae968378b..64485afeb0 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -37,14 +37,26 @@
A list of additional command line arguments, exported project will receive when started.
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
- Path to the custom export template. If left empty, default template is used.
+ Path to an APK file to use as a custom export template for debug exports. If left empty, default template is used.
+ [b]Note:[/b] This is only used if [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] is disabled.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
- Path to the custom export template. If left empty, default template is used.
+ Path to an APK file to use as a custom export template for release exports. If left empty, default template is used.
+ [b]Note:[/b] This is only used if [member EditorExportPlatformAndroid.gradle_build/use_gradle_build] is disabled.
+ </member>
+ <member name="gradle_build/android_source_template" type="String" setter="" getter="">
+ Path to a ZIP file holding the source for the export template used in a Gradle build. If left empty, the default template is used.
+ </member>
+ <member name="gradle_build/compress_native_libraries" type="bool" setter="" getter="">
+ If [code]true[/code], native libraries are compressed when performing a Gradle build.
+ [b]Note:[/b] Although your binary may be smaller, your application may load slower because the native libraries are not loaded directly from the binary at runtime.
</member>
<member name="gradle_build/export_format" type="int" setter="" getter="">
Export format for Gradle build.
</member>
+ <member name="gradle_build/gradle_build_directory" type="String" setter="" getter="">
+ Path to the Gradle build directory. If left empty, then [code]res://android[/code] will be used.
+ </member>
<member name="gradle_build/min_sdk" type="String" setter="" getter="">
Minimal Android SDK version for Gradle build.
</member>
@@ -119,7 +131,10 @@
If [code]true[/code], package signing is enabled.
</member>
<member name="package/unique_name" type="String" setter="" getter="">
- Unique application identifier in a reverse-DNS format, can only contain alphanumeric characters ([code]A-Z[/code], [code]a-z[/code], and [code]0-9[/code]), hyphens ([code]-[/code]), and periods ([code].[/code]).
+ Unique application identifier in a reverse-DNS format. The reverse DNS format should preferably match a domain name you control, but this is not strictly required. For instance, if you own [code]example.com[/code], your package unique name should preferably be of the form [code]com.example.mygame[/code]. This identifier can only contain lowercase alphanumeric characters ([code]a-z[/code], and [code]0-9[/code]), underscores ([code]_[/code]), and periods ([code].[/code]). Each component of the reverse DNS format must start with a letter: for instance, [code]com.example.8game[/code] is not valid.
+ If [code]$genname[/code] is present in the value, it will be replaced by the project name converted to lowercase. If there are invalid characters in the project name, they will be stripped. If all characters in the project name are stripped, [code]$genname[/code] is replaced by [code]noname[/code].
+ [b]Note:[/b] Changing the package name will cause the package to be considered as a new package, with its own installation and data paths. The new package won't be usable to update existing installations.
+ [b]Note:[/b] When publishing to Google Play, the package name must be [i]globally[/i] unique. This means no other apps published on Google Play must be using the same package name as yours. Otherwise, you'll be prevented from publishing your app on Google Play.
</member>
<member name="permissions/access_checkin_properties" type="bool" setter="" getter="">
Allows read/write access to the "properties" table in the checkin database. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_CHECKIN_PROPERTIES]ACCESS_CHECKIN_PROPERTIES[/url].
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 00e837825b..d0db7b2e6c 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -46,6 +46,7 @@
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
+#include "editor/export/export_template_manager.h"
#include "editor/import/resource_importer_texture_settings.h"
#include "editor/themes/editor_scale.h"
#include "main/splash.gen.h"
@@ -208,12 +209,14 @@ static const char *android_perms[] = {
nullptr
};
+static const char *MISMATCHED_VERSIONS_MESSAGE = "Android build version mismatch:\n| Template installed: %s\n| Requested version: %s\nPlease reinstall Android build template from 'Project' menu.";
+
static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi/splash.png";
static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v4/splash.png";
static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
-static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
-static const char *GDEXTENSION_LIBS_PATH = "res://android/build/libs/gdextensionlibs.json";
+static const char *SPLASH_CONFIG_PATH = "res/drawable/splash_drawable.xml";
+static const char *GDEXTENSION_LIBS_PATH = "libs/gdextensionlibs.json";
static const int icon_densities_count = 6;
static const char *launcher_icon_option = PNAME("launcher_icons/main_192x192");
@@ -250,8 +253,8 @@ static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_coun
static const int EXPORT_FORMAT_APK = 0;
static const int EXPORT_FORMAT_AAB = 1;
-static const char *APK_ASSETS_DIRECTORY = "res://android/build/assets";
-static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/installTime/src/main/assets";
+static const char *APK_ASSETS_DIRECTORY = "assets";
+static const char *AAB_ASSETS_DIRECTORY = "assetPacks/installTime/src/main/assets";
static const int OPENGL_MIN_SDK_VERSION = 21; // Should match the value in 'platform/android/java/app/config.gradle#minSdk'
static const int VULKAN_MIN_SDK_VERSION = 24;
@@ -493,7 +496,8 @@ String EditorExportPlatformAndroid::get_valid_basename() const {
}
String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const {
- return p_export_format == EXPORT_FORMAT_AAB ? AAB_ASSETS_DIRECTORY : APK_ASSETS_DIRECTORY;
+ String gradle_build_directory = ExportTemplateManager::get_android_build_directory(p_preset);
+ return gradle_build_directory.path_join(p_export_format == EXPORT_FORMAT_AAB ? AAB_ASSETS_DIRECTORY : APK_ASSETS_DIRECTORY);
}
bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const {
@@ -793,11 +797,10 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
}
if (abi_index != -1) {
exported = true;
- String base = "res://android/build/libs";
String type = export_data->debug ? "debug" : "release";
String abi = abis[abi_index].abi;
String filename = p_so.path.get_file();
- String dst_path = base.path_join(type).path_join(abi).path_join(filename);
+ String dst_path = export_data->libs_directory.path_join(type).path_join(abi).path_join(filename);
Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_so.path);
print_verbose("Copying .so file from " + p_so.path + " to " + dst_path);
Error err = store_file_at_path(dst_path, data);
@@ -895,7 +898,7 @@ void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPres
manifest_text += _get_application_tag(Ref<EditorExportPlatform>(this), p_preset, _has_read_write_storage_permission(perms), p_debug);
manifest_text += "</manifest>\n";
- String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
+ String manifest_path = ExportTemplateManager::get_android_build_directory(p_preset).path_join(vformat("src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release")));
print_verbose("Storing manifest into " + manifest_path + ": " + "\n" + manifest_text);
store_string_at_path(manifest_path, manifest_text);
@@ -1656,15 +1659,6 @@ void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &
}
}
-void EditorExportPlatformAndroid::store_image(const LauncherIcon launcher_icon, const Vector<uint8_t> &data) {
- store_image(launcher_icon.export_path, data);
-}
-
-void EditorExportPlatformAndroid::store_image(const String &export_path, const Vector<uint8_t> &data) {
- String img_path = export_path.insert(0, "res://android/build/");
- store_file_at_path(img_path, data);
-}
-
void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
const String &processed_splash_config_xml,
const Ref<Image> &splash_image,
@@ -1672,26 +1666,30 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
const Ref<Image> &main_image,
const Ref<Image> &foreground,
const Ref<Image> &background) {
+ String gradle_build_dir = ExportTemplateManager::get_android_build_directory(p_preset);
+
// Store the splash configuration
if (!processed_splash_config_xml.is_empty()) {
print_verbose("Storing processed splash configuration: " + String("\n") + processed_splash_config_xml);
- store_string_at_path(SPLASH_CONFIG_PATH, processed_splash_config_xml);
+ store_string_at_path(gradle_build_dir.path_join(SPLASH_CONFIG_PATH), processed_splash_config_xml);
}
// Store the splash image
if (splash_image.is_valid() && !splash_image->is_empty()) {
- print_verbose("Storing splash image in " + String(SPLASH_IMAGE_EXPORT_PATH));
+ String splash_export_path = gradle_build_dir.path_join(SPLASH_IMAGE_EXPORT_PATH);
+ print_verbose("Storing splash image in " + splash_export_path);
Vector<uint8_t> data;
_load_image_data(splash_image, data);
- store_image(SPLASH_IMAGE_EXPORT_PATH, data);
+ store_file_at_path(splash_export_path, data);
}
// Store the splash bg color image
if (splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
- print_verbose("Storing splash background image in " + String(SPLASH_BG_COLOR_PATH));
+ String splash_bg_color_path = gradle_build_dir.path_join(SPLASH_BG_COLOR_PATH);
+ print_verbose("Storing splash background image in " + splash_bg_color_path);
Vector<uint8_t> data;
_load_image_data(splash_bg_color_image, data);
- store_image(SPLASH_BG_COLOR_PATH, data);
+ store_file_at_path(splash_bg_color_path, data);
}
// Prepare images to be resized for the icons. If some image ends up being uninitialized,
@@ -1702,7 +1700,7 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
print_verbose("Processing launcher icon for dimension " + itos(launcher_icons[i].dimensions) + " into " + launcher_icons[i].export_path);
Vector<uint8_t> data;
_process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data);
- store_image(launcher_icons[i], data);
+ store_file_at_path(gradle_build_dir.path_join(launcher_icons[i].export_path), data);
}
if (foreground.is_valid() && !foreground->is_empty()) {
@@ -1710,7 +1708,7 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
Vector<uint8_t> data;
_process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground,
launcher_adaptive_icon_foregrounds[i].dimensions, data);
- store_image(launcher_adaptive_icon_foregrounds[i], data);
+ store_file_at_path(gradle_build_dir.path_join(launcher_adaptive_icon_foregrounds[i].export_path), data);
}
if (background.is_valid() && !background->is_empty()) {
@@ -1718,7 +1716,7 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
Vector<uint8_t> data;
_process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background,
launcher_adaptive_icon_backgrounds[i].dimensions, data);
- store_image(launcher_adaptive_icon_backgrounds[i], data);
+ store_file_at_path(gradle_build_dir.path_join(launcher_adaptive_icon_backgrounds[i].export_path), data);
}
}
}
@@ -1772,6 +1770,11 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
if (xr_mode_index == XR_MODE_OPENXR && !gradle_build_enabled) {
return TTR("OpenXR requires \"Use Gradle Build\" to be enabled");
}
+ } else if (p_name == "gradle_build/compress_native_libraries") {
+ bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
+ if (bool(p_preset->get("gradle_build/compress_native_libraries")) && !gradle_build_enabled) {
+ return TTR("\"Compress Native Libraries\" is only valid when \"Use Gradle Build\" is enabled.");
+ }
} else if (p_name == "gradle_build/export_format") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
if (int(p_preset->get("gradle_build/export_format")) == EXPORT_FORMAT_AAB && !gradle_build_enabled) {
@@ -1826,7 +1829,10 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
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, "gradle_build/use_gradle_build"), false, false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/use_gradle_build"), false, true, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/gradle_build_directory", PROPERTY_HINT_PLACEHOLDER_TEXT, "res://android"), "", false, false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/android_source_template", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/compress_native_libraries"), false, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK, false, true));
// Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465).
// This implies doing validation that the string is a proper int.
@@ -1904,6 +1910,18 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
}
}
+bool EditorExportPlatformAndroid::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
+ if (p_option == "gradle_build/gradle_build_directory" || p_option == "gradle_build/android_source_template") {
+ // @todo These are experimental options - keep them hidden for now.
+ //return (bool)p_preset->get("gradle_build/use_gradle_build");
+ return false;
+ } else if (p_option == "custom_template/debug" || p_option == "custom_template/release") {
+ // The APK templates are ignored if Gradle build is enabled.
+ return !p_preset->get("gradle_build/use_gradle_build");
+ }
+ return true;
+}
+
String EditorExportPlatformAndroid::get_name() const {
return "Android";
}
@@ -2373,7 +2391,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
err += template_err;
}
} else {
- bool installed_android_build_template = FileAccess::exists("res://android/build/build.gradle");
+ bool installed_android_build_template = FileAccess::exists(ExportTemplateManager::get_android_build_directory(p_preset).path_join("build.gradle"));
if (!installed_android_build_template) {
r_missing_templates = !exists_export_template("android_source.zip", &err);
err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n";
@@ -2520,6 +2538,19 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
valid = false;
}
+ if (p_preset->get("gradle_build/use_gradle_build")) {
+ String build_version_path = ExportTemplateManager::get_android_build_directory(p_preset).get_base_dir().path_join(".build_version");
+ Ref<FileAccess> f = FileAccess::open(build_version_path, FileAccess::READ);
+ if (f.is_valid()) {
+ String current_version = ExportTemplateManager::get_android_template_identifier(p_preset);
+ String installed_version = f->get_line().strip_edges();
+ if (current_version != installed_version) {
+ err += vformat(TTR(MISMATCHED_VERSIONS_MESSAGE), installed_version, current_version);
+ err += "\n";
+ }
+ }
+ }
+
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
int min_sdk_int = VULKAN_MIN_SDK_VERSION;
if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do.
@@ -2762,34 +2793,37 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
return OK;
}
-void EditorExportPlatformAndroid::_clear_assets_directory() {
+void EditorExportPlatformAndroid::_clear_assets_directory(const Ref<EditorExportPreset> &p_preset) {
Ref<DirAccess> da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ String gradle_build_directory = ExportTemplateManager::get_android_build_directory(p_preset);
// Clear the APK assets directory
- if (da_res->dir_exists(APK_ASSETS_DIRECTORY)) {
+ String apk_assets_directory = gradle_build_directory.path_join(APK_ASSETS_DIRECTORY);
+ if (da_res->dir_exists(apk_assets_directory)) {
print_verbose("Clearing APK assets directory...");
- Ref<DirAccess> da_assets = DirAccess::open(APK_ASSETS_DIRECTORY);
+ Ref<DirAccess> da_assets = DirAccess::open(apk_assets_directory);
ERR_FAIL_COND(da_assets.is_null());
da_assets->erase_contents_recursive();
- da_res->remove(APK_ASSETS_DIRECTORY);
+ da_res->remove(apk_assets_directory);
}
// Clear the AAB assets directory
- if (da_res->dir_exists(AAB_ASSETS_DIRECTORY)) {
+ String aab_assets_directory = gradle_build_directory.path_join(AAB_ASSETS_DIRECTORY);
+ if (da_res->dir_exists(aab_assets_directory)) {
print_verbose("Clearing AAB assets directory...");
- Ref<DirAccess> da_assets = DirAccess::open(AAB_ASSETS_DIRECTORY);
+ Ref<DirAccess> da_assets = DirAccess::open(aab_assets_directory);
ERR_FAIL_COND(da_assets.is_null());
da_assets->erase_contents_recursive();
- da_res->remove(AAB_ASSETS_DIRECTORY);
+ da_res->remove(aab_assets_directory);
}
}
-void EditorExportPlatformAndroid::_remove_copied_libs() {
+void EditorExportPlatformAndroid::_remove_copied_libs(String p_gdextension_libs_path) {
print_verbose("Removing previously installed libraries...");
Error error;
- String libs_json = FileAccess::get_file_as_string(GDEXTENSION_LIBS_PATH, &error);
+ String libs_json = FileAccess::get_file_as_string(p_gdextension_libs_path, &error);
if (error || libs_json.is_empty()) {
print_verbose("No previously installed libraries found");
return;
@@ -2805,7 +2839,7 @@ void EditorExportPlatformAndroid::_remove_copied_libs() {
print_verbose("Removing previously installed library " + libs[i]);
da->remove(libs[i]);
}
- da->remove(GDEXTENSION_LIBS_PATH);
+ da->remove(p_gdextension_libs_path);
}
String EditorExportPlatformAndroid::join_list(const List<String> &p_parts, const String &p_separator) {
@@ -2864,6 +2898,8 @@ String EditorExportPlatformAndroid::_resolve_export_plugin_android_library_path(
bool EditorExportPlatformAndroid::_is_clean_build_required(const Ref<EditorExportPreset> &p_preset) {
bool first_build = last_gradle_build_time == 0;
bool have_plugins_changed = false;
+ String gradle_build_dir = ExportTemplateManager::get_android_build_directory(p_preset);
+ bool has_build_dir_changed = last_gradle_build_dir != gradle_build_dir;
String plugin_names = _get_plugins_names(p_preset);
@@ -2883,9 +2919,10 @@ bool EditorExportPlatformAndroid::_is_clean_build_required(const Ref<EditorExpor
}
last_gradle_build_time = OS::get_singleton()->get_unix_time();
+ last_gradle_build_dir = gradle_build_dir;
last_plugin_names = plugin_names;
- return have_plugins_changed || first_build;
+ return have_plugins_changed || has_build_dir_changed || first_build;
}
Error EditorExportPlatformAndroid::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
@@ -2909,6 +2946,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
EditorProgress ep("export", TTR("Exporting for Android"), 105, true);
bool use_gradle_build = bool(p_preset->get("gradle_build/use_gradle_build"));
+ String gradle_build_directory = use_gradle_build ? ExportTemplateManager::get_android_build_directory(p_preset) : "";
bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
bool apk_expansion = p_preset->get("apk_expansion/enable");
Vector<ABI> enabled_abis = get_enabled_abis(p_preset);
@@ -2968,15 +3006,17 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
//test that installed build version is alright
{
print_verbose("Checking build version...");
- Ref<FileAccess> f = FileAccess::open("res://android/.build_version", FileAccess::READ);
+ String gradle_base_directory = gradle_build_directory.get_base_dir();
+ Ref<FileAccess> f = FileAccess::open(gradle_base_directory.path_join(".build_version"), FileAccess::READ);
if (f.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Trying to build from a gradle built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
return ERR_UNCONFIGURED;
}
- String version = f->get_line().strip_edges();
- print_verbose("- build version: " + version);
- if (version != VERSION_FULL_CONFIG) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Android build version mismatch: Template installed: %s, Godot version: %s. Please reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
+ String current_version = ExportTemplateManager::get_android_template_identifier(p_preset);
+ String installed_version = f->get_line().strip_edges();
+ print_verbose("- build version: " + installed_version);
+ if (installed_version != current_version) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR(MISMATCHED_VERSIONS_MESSAGE), installed_version, current_version));
return ERR_UNCONFIGURED;
}
}
@@ -2997,9 +3037,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
// TODO: should we use "package/name" or "application/config/name"?
String project_name = get_project_name(p_preset->get("package/name"));
- err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
+ err = _create_project_name_strings_files(p_preset, project_name, gradle_build_directory); //project name localization.
if (err != OK) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to overwrite res://android/build/res/*.xml files with project name."));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to overwrite res/*.xml files with project name."));
}
// Copies the project icon files into the appropriate Gradle project directory.
_copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
@@ -3007,12 +3047,14 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_write_tmp_manifest(p_preset, p_give_internet, p_debug);
//stores all the project files inside the Gradle project directory. Also includes all ABIs
- _clear_assets_directory();
- _remove_copied_libs();
+ _clear_assets_directory(p_preset);
+ String gdextension_libs_path = gradle_build_directory.path_join(GDEXTENSION_LIBS_PATH);
+ _remove_copied_libs(gdextension_libs_path);
if (!apk_expansion) {
print_verbose("Exporting project files...");
CustomExportData user_data;
user_data.assets_directory = assets_directory;
+ user_data.libs_directory = gradle_build_directory.path_join("libs");
user_data.debug = p_debug;
if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
err = export_project_files(p_preset, p_debug, ignore_apk_file, &user_data, copy_gradle_so);
@@ -3051,7 +3093,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
build_command = "gradlew";
#endif
- String build_path = ProjectSettings::get_singleton()->get_resource_path().path_join("android/build");
+ String build_path = ProjectSettings::get_singleton()->globalize_path(gradle_build_directory);
build_command = build_path.path_join(build_command);
String package_name = get_package_name(p_preset->get("package/unique_name"));
@@ -3068,6 +3110,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String enabled_abi_string = join_abis(enabled_abis, "|", false);
String sign_flag = should_sign ? "true" : "false";
String zipalign_flag = "true";
+ String compress_native_libraries_flag = bool(p_preset->get("gradle_build/compress_native_libraries")) ? "true" : "false";
Vector<String> android_libraries;
Vector<String> android_dependencies;
@@ -3132,6 +3175,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
cmdline.push_back("-Pplugins_maven_repos=" + combined_android_dependencies_maven_repos); // argument to specify the list of maven repos for android dependencies provided by plugins.
cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned.
cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed.
+ cmdline.push_back("-Pcompress_native_libraries=" + compress_native_libraries_flag); // argument to specify whether the build should compress native libraries.
cmdline.push_back("-Pgodot_editor_version=" + String(VERSION_FULL_CONFIG));
// NOTE: The release keystore is not included in the verbose logging
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 8490ecc356..e25655c6cc 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -90,6 +90,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
#endif // DISABLE_DEPRECATED
String last_plugin_names;
uint64_t last_gradle_build_time = 0;
+ String last_gradle_build_dir;
Vector<Device> devices;
SafeFlag devices_changed;
@@ -176,10 +177,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background);
- void store_image(const LauncherIcon launcher_icon, const Vector<uint8_t> &data);
-
- void store_image(const String &export_path, const Vector<uint8_t> &data);
-
void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
const String &processed_splash_config_xml,
const Ref<Image> &splash_image,
@@ -202,6 +199,8 @@ public:
virtual void get_export_options(List<ExportOption> *r_options) const override;
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
+
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
virtual String get_name() const override;
@@ -252,9 +251,9 @@ public:
Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep);
- void _clear_assets_directory();
+ void _clear_assets_directory(const Ref<EditorExportPreset> &p_preset);
- void _remove_copied_libs();
+ void _remove_copied_libs(String p_gdextension_libs_path);
static String join_list(const List<String> &p_parts, const String &p_separator);
static String join_abis(const Vector<ABI> &p_parts, const String &p_separator, bool p_use_arch);
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 0915009235..9eddef6a4c 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -191,14 +191,14 @@ String _android_xml_escape(const String &p_string) {
}
// Creates strings.xml files inside the gradle project for different locales.
-Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name) {
+Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name, const String &p_gradle_build_dir) {
print_verbose("Creating strings resources for supported locales for project " + project_name);
// Stores the string into the default values directory.
String processed_default_xml_string = vformat(godot_project_name_xml_string, _android_xml_escape(project_name));
- store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string);
+ store_string_at_path(p_gradle_build_dir.path_join("res/values/godot_project_name_string.xml"), processed_default_xml_string);
// Searches the Gradle project res/ directory to find all supported locales
- Ref<DirAccess> da = DirAccess::open("res://android/build/res");
+ Ref<DirAccess> da = DirAccess::open(p_gradle_build_dir.path_join("res"));
if (da.is_null()) {
if (OS::get_singleton()->is_stdout_verbose()) {
print_error("Unable to open Android resources directory.");
@@ -217,7 +217,7 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
continue;
}
String locale = file.replace("values-", "").replace("-r", "_");
- String locale_directory = "res://android/build/res/" + file + "/godot_project_name_string.xml";
+ String locale_directory = p_gradle_build_dir.path_join("res/" + file + "/godot_project_name_string.xml");
if (appnames.has(locale)) {
String locale_project_name = appnames[locale];
String processed_xml_string = vformat(godot_project_name_xml_string, _android_xml_escape(locale_project_name));
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 2498394add..9f8e476f73 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -63,6 +63,7 @@ static const int XR_MODE_OPENXR = 1;
struct CustomExportData {
String assets_directory;
+ String libs_directory;
bool debug;
Vector<String> libs;
};
@@ -94,7 +95,7 @@ Error store_string_at_path(const String &p_path, const String &p_data);
Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
// Creates strings.xml files inside the gradle project for different locales.
-Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name);
+Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name, const String &p_gradle_build_dir);
String bool_to_string(bool v);
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index f084c60209..7797f4bc9d 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -116,6 +116,14 @@ android {
if (shouldNotStrip()) {
doNotStrip '**/*.so'
}
+
+ jniLibs {
+ // Setting this to true causes AGP to package compressed native libraries when building the app
+ // For more background, see:
+ // - https://developer.android.com/build/releases/past-releases/agp-3-6-0-release-notes#extractNativeLibs
+ // - https://stackoverflow.com/a/44704840
+ useLegacyPackaging shouldUseLegacyPackaging()
+ }
}
signingConfigs {
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 7224765f28..f2c4a5d1b6 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -361,3 +361,26 @@ ext.shouldSign = { ->
ext.shouldNotStrip = { ->
return isAndroidStudio() || project.hasProperty("doNotStrip")
}
+
+/**
+ * Whether to use the legacy convention of compressing all .so files in the APK.
+ *
+ * For more background, see:
+ * - https://developer.android.com/build/releases/past-releases/agp-3-6-0-release-notes#extractNativeLibs
+ * - https://stackoverflow.com/a/44704840
+ */
+ext.shouldUseLegacyPackaging = { ->
+ int minSdk = getExportMinSdkVersion()
+ if (minSdk < 23) {
+ // Enforce the default behavior for compatibility with device running api < 23
+ return true
+ }
+
+ String legacyPackagingFlag = project.hasProperty("compress_native_libraries") ? project.property("compress_native_libraries") : ""
+ if (legacyPackagingFlag != null && !legacyPackagingFlag.isEmpty()) {
+ return Boolean.parseBoolean(legacyPackagingFlag)
+ }
+
+ // Default behavior for minSdk >= 23
+ return false
+}
diff --git a/platform/android/java/app/gradle.properties b/platform/android/java/app/gradle.properties
index d9f79b6818..2b6468c95e 100644
--- a/platform/android/java/app/gradle.properties
+++ b/platform/android/java/app/gradle.properties
@@ -23,3 +23,6 @@ org.gradle.warning.mode=all
# Enable resource optimizations for release build.
# NOTE: This is turned off for template release build in order to support the build legacy process.
android.enableResourceOptimizations=true
+
+# Fix gradle build errors when the build path contains non-ASCII characters
+android.overridePathCheck=true
diff --git a/platform/android/java/gradle.properties b/platform/android/java/gradle.properties
index 39a0dcda16..c8abb52614 100644
--- a/platform/android/java/gradle.properties
+++ b/platform/android/java/gradle.properties
@@ -26,3 +26,6 @@ org.gradle.warning.mode=all
# Disable resource optimizations for template release build.
# NOTE: This is turned on for Godot Editor's gradle builds in order to improve the release build.
android.enableResourceOptimizations=false
+
+# Fix gradle build errors when the build path contains non-ASCII characters
+android.overridePathCheck=true
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 61ae0cd58a..ed967b9660 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -101,6 +101,7 @@ android {
}
boolean devBuild = buildType == "dev"
+ boolean debugSymbols = devBuild || isAndroidStudio()
boolean runTests = devBuild
boolean productionBuild = !devBuild
boolean storeRelease = buildType == "release"
@@ -168,7 +169,7 @@ android {
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
tasks.create(name: taskName, type: Exec) {
executable sconsExecutableFile.absolutePath
- args "--directory=${pathToRootDir}", "platform=android", "store_release=${storeRelease}", "production=${productionBuild}", "dev_mode=${devBuild}", "dev_build=${devBuild}", "tests=${runTests}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
+ args "--directory=${pathToRootDir}", "platform=android", "store_release=${storeRelease}", "production=${productionBuild}", "dev_mode=${devBuild}", "dev_build=${devBuild}", "debug_symbols=${debugSymbols}", "tests=${runTests}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
}
// Schedule the tasks so the generated libs are present before the aar file is packaged.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index da86e67c7d..e2e77e7796 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -37,6 +37,7 @@ import android.content.*
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
+import android.graphics.Color
import android.graphics.Rect
import android.hardware.Sensor
import android.hardware.SensorEvent
@@ -149,6 +150,7 @@ class Godot(private val context: Context) : SensorEventListener {
private var useApkExpansion = false
private var useImmersive = false
private var useDebugOpengl = false
+ private var darkMode = false;
private var containerLayout: FrameLayout? = null
var renderView: GodotRenderView? = null
@@ -184,6 +186,8 @@ class Godot(private val context: Context) : SensorEventListener {
return
}
+ darkMode = context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
+
beginBenchmarkMeasure("Startup", "Godot::onCreate")
try {
this.primaryHost = primaryHost
@@ -376,6 +380,8 @@ class Godot(private val context: Context) : SensorEventListener {
ViewGroup.LayoutParams.MATCH_PARENT,
activity.resources.getDimension(R.dimen.text_edit_height).toInt()
)
+ // Prevent GodotEditText from showing on splash screen on devices with Android 14 or newer.
+ editText.setBackgroundColor(Color.TRANSPARENT)
// ...add to FrameLayout
containerLayout?.addView(editText)
renderView = if (usesVulkan()) {
@@ -560,6 +566,17 @@ class Godot(private val context: Context) : SensorEventListener {
}
/**
+ * Configuration change callback
+ */
+ fun onConfigurationChanged(newConfig: Configuration) {
+ var newDarkMode = newConfig.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
+ if (darkMode != newDarkMode) {
+ darkMode = newDarkMode
+ GodotLib.onNightModeChanged()
+ }
+ }
+
+ /**
* Activity result callback
*/
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -596,11 +613,13 @@ class Godot(private val context: Context) : SensorEventListener {
// These properties are defined after Godot setup completion, so we retrieve them here.
val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
+ val rotaryInputAxis = java.lang.Integer.parseInt(GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis"));
runOnUiThread {
renderView?.inputHandler?.apply {
enableLongPress(longPressEnabled)
enablePanningAndScalingGestures(panScaleEnabled)
+ setRotaryInputAxis(rotaryInputAxis)
}
}
@@ -731,7 +750,7 @@ class Godot(private val context: Context) : SensorEventListener {
*/
@Keep
private fun isDarkModeSupported(): Boolean {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
+ return context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) != Configuration.UI_MODE_NIGHT_UNDEFINED
}
/**
@@ -739,10 +758,7 @@ class Godot(private val context: Context) : SensorEventListener {
*/
@Keep
private fun isDarkMode(): Boolean {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- return context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
- }
- return false
+ return darkMode
}
fun hasClipboard(): Boolean {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
index 643c9a658e..a323045e1b 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
@@ -38,6 +38,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.os.Messenger;
@@ -147,6 +148,13 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH
@CallSuper
@Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ godot.onConfigurationChanged(newConfig);
+ }
+
+ @CallSuper
+ @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCallback != null) {
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 fee50e93c2..d0c3d4a687 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -220,6 +220,11 @@ public class GodotLib {
public static native void requestPermissionResult(String p_permission, boolean p_result);
/**
+ * Invoked on the theme light/dark mode change.
+ */
+ public static native void onNightModeChanged();
+
+ /**
* Invoked on the GL thread to configure the height of the virtual keyboard.
*/
public static native void setVirtualKeyboardHeight(int p_height);
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 3070a8a207..dc8a0e54bb 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
@@ -34,10 +34,13 @@ import org.godotengine.godot.*;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.InputFilter;
import android.text.InputType;
+import android.text.TextUtils;
+import android.text.method.DigitsKeyListener;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
@@ -45,6 +48,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import java.lang.ref.WeakReference;
+import java.util.Locale;
public class GodotEditText extends EditText {
// ===========================================================
@@ -137,6 +141,7 @@ public class GodotEditText extends EditText {
}
int inputType = InputType.TYPE_CLASS_TEXT;
+ String acceptCharacters = null;
switch (edit.getKeyboardType()) {
case KEYBOARD_TYPE_DEFAULT:
inputType = InputType.TYPE_CLASS_TEXT;
@@ -148,7 +153,8 @@ public class GodotEditText extends EditText {
inputType = InputType.TYPE_CLASS_NUMBER;
break;
case KEYBOARD_TYPE_NUMBER_DECIMAL:
- inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED;
+ inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL;
+ acceptCharacters = "0123456789,.- ";
break;
case KEYBOARD_TYPE_PHONE:
inputType = InputType.TYPE_CLASS_PHONE;
@@ -165,6 +171,14 @@ public class GodotEditText extends EditText {
}
edit.setInputType(inputType);
+ if (!TextUtils.isEmpty(acceptCharacters)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ edit.setKeyListener(DigitsKeyListener.getInstance(Locale.getDefault()));
+ } else {
+ edit.setKeyListener(DigitsKeyListener.getInstance(acceptCharacters));
+ }
+ }
+
edit.mInputWrapper.setOriginText(text);
edit.addTextChangedListener(edit.mInputWrapper);
final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
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 38c115ad7f..fe971cf442 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
@@ -57,6 +57,9 @@ import java.util.Set;
public class GodotInputHandler implements InputManager.InputDeviceListener {
private static final String TAG = GodotInputHandler.class.getSimpleName();
+ private static final int ROTARY_INPUT_VERTICAL_AXIS = 1;
+ private static final int ROTARY_INPUT_HORIZONTAL_AXIS = 0;
+
private final SparseIntArray mJoystickIds = new SparseIntArray(4);
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
@@ -71,6 +74,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
*/
private int lastSeenToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+ private static int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS;
+
public GodotInputHandler(GodotRenderView godotView) {
final Context context = godotView.getView().getContext();
mRenderView = godotView;
@@ -102,6 +107,13 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
this.godotGestureHandler.setPanningAndScalingEnabled(enable);
}
+ /**
+ * On Wear OS devices, sets which axis of the mouse wheel rotary input is mapped to. This is 1 (vertical axis) by default.
+ */
+ public void setRotaryInputAxis(int axis) {
+ rotaryInputAxis = axis;
+ }
+
private boolean isKeyEventGameDevice(int source) {
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
@@ -484,8 +496,22 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final float tiltX = (float)-Math.sin(orientation) * tiltMult;
final float tiltY = (float)Math.cos(orientation) * tiltMult;
- final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
- final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ float verticalFactor = 0;
+ float horizontalFactor = 0;
+
+ // If event came from RotaryEncoder (Bezel or Crown rotate event on Wear OS smart watches),
+ // convert it to mouse wheel event.
+ if (event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER)) {
+ if (rotaryInputAxis == ROTARY_INPUT_HORIZONTAL_AXIS) {
+ horizontalFactor = -event.getAxisValue(MotionEvent.AXIS_SCROLL);
+ } else {
+ // If rotaryInputAxis is not ROTARY_INPUT_HORIZONTAL_AXIS then use default ROTARY_INPUT_VERTICAL_AXIS axis.
+ verticalFactor = -event.getAxisValue(MotionEvent.AXIS_SCROLL);
+ }
+ } else {
+ verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ }
boolean sourceMouseRelative = false;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 08e792cc04..85d5cf2796 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -487,6 +487,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
Callable(obj, str_method).call_deferredp(argptrs, count);
}
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JNIEnv *env, jclass clazz) {
+ DisplayServerAndroid *ds = (DisplayServerAndroid *)DisplayServer::get_singleton();
+ if (ds) {
+ ds->emit_system_theme_changed();
+ }
+}
+
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) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 1ddda6c1c8..f32ffc291a 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -66,6 +66,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong 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_onNightModeChanged(JNIEnv *env, jclass clazz);
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/net_socket_android.cpp b/platform/android/net_socket_android.cpp
index 1299ad032a..a2befdc9be 100644
--- a/platform/android/net_socket_android.cpp
+++ b/platform/android/net_socket_android.cpp
@@ -106,7 +106,7 @@ Error NetSocketAndroid::set_broadcasting_enabled(bool p_enabled) {
return OK;
}
-Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
+Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
Error err = NetSocketPosix::join_multicast_group(p_multi_address, p_if_name);
if (err != OK) {
return err;
@@ -120,7 +120,7 @@ Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, S
return OK;
}
-Error NetSocketAndroid::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
+Error NetSocketAndroid::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
Error err = NetSocketPosix::leave_multicast_group(p_multi_address, p_if_name);
if (err != OK) {
return err;
diff --git a/platform/android/net_socket_android.h b/platform/android/net_socket_android.h
index f0c2b70529..e5f46d3236 100644
--- a/platform/android/net_socket_android.h
+++ b/platform/android/net_socket_android.h
@@ -67,8 +67,8 @@ public:
virtual void close();
virtual Error set_broadcasting_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name);
- virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name);
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name);
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name);
NetSocketAndroid() {}
~NetSocketAndroid();
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 0d82bec75d..82e7fdb320 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -162,7 +162,7 @@ Vector<String> OS_Android::get_granted_permissions() const {
return godot_java->get_granted_permissions();
}
-Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
+Error OS_Android::open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = p_path;
bool so_file_exists = true;
if (!FileAccess::exists(path)) {
@@ -324,15 +324,21 @@ void OS_Android::main_loop_end() {
void OS_Android::main_loop_focusout() {
DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
+ }
audio_driver_android.set_pause(true);
}
void OS_Android::main_loop_focusin() {
DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
+ }
audio_driver_android.set_pause(false);
}
-Error OS_Android::shell_open(String p_uri) {
+Error OS_Android::shell_open(const String &p_uri) {
return godot_io_java->open_uri(p_uri);
}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 837ef8bad5..31ee7389df 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -113,7 +113,7 @@ public:
virtual void alert(const String &p_alert, const String &p_title) override;
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
+ virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
virtual String get_name() const override;
virtual String get_distribution_name() const override;
@@ -134,7 +134,7 @@ public:
void set_native_window(ANativeWindow *p_native_window);
ANativeWindow *get_native_window() const;
- virtual Error shell_open(String p_uri) override;
+ virtual Error shell_open(const String &p_uri) override;
virtual Vector<String> get_system_fonts() const override;
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
diff --git a/platform/android/vulkan_context_android.cpp b/platform/android/rendering_context_driver_vulkan_android.cpp
index 4f9140bf3e..9232126b04 100644
--- a/platform/android/vulkan_context_android.cpp
+++ b/platform/android/rendering_context_driver_vulkan_android.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_android.cpp */
+/* rendering_context_driver_vulkan_android.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "vulkan_context_android.h"
+#include "rendering_context_driver_vulkan_android.h"
#ifdef VULKAN_ENABLED
@@ -38,32 +38,32 @@
#include <vulkan/vulkan.h>
#endif
-const char *VulkanContextAndroid::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanAndroid::_get_platform_surface_extension() const {
return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
}
-Error VulkanContextAndroid::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
- const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAndroid::surface_create(const void *p_platform_data) {
+ const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
- VkAndroidSurfaceCreateInfoKHR createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
- createInfo.window = wpd->window;
+ VkAndroidSurfaceCreateInfoKHR create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ create_info.window = wpd->window;
- VkSurfaceKHR surface = VK_NULL_HANDLE;
- VkResult err = vkCreateAndroidSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
- if (err != VK_SUCCESS) {
- ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
- }
+ VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+ VkResult err = vkCreateAndroidSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
- return _window_create(DisplayServer::MAIN_WINDOW_ID, p_vsync_mode, surface, p_width, p_height);
+ Surface *surface = memnew(Surface);
+ surface->vk_surface = vk_surface;
+ return SurfaceID(surface);
}
-bool VulkanContextAndroid::_use_validation_layers() {
- uint32_t count = 0;
- _get_preferred_validation_layers(&count, nullptr);
+bool RenderingContextDriverVulkanAndroid::_use_validation_layers() const {
+ TightLocalVector<const char *> layer_names;
+ Error err = _find_validation_layers(layer_names);
// On Android, we use validation layers automatically if they were explicitly linked with the app.
- return count > 0;
+ return (err == OK) && !layer_names.is_empty();
}
#endif // VULKAN_ENABLED
diff --git a/platform/android/vulkan_context_android.h b/platform/android/rendering_context_driver_vulkan_android.h
index 3cee3feb86..a2a42eef24 100644
--- a/platform/android/vulkan_context_android.h
+++ b/platform/android/rendering_context_driver_vulkan_android.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_android.h */
+/* rendering_context_driver_vulkan_android.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,31 +28,32 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef VULKAN_CONTEXT_ANDROID_H
-#define VULKAN_CONTEXT_ANDROID_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_ANDROID_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_ANDROID_H
#ifdef VULKAN_ENABLED
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
struct ANativeWindow;
-class VulkanContextAndroid : public VulkanContext {
+class RenderingContextDriverVulkanAndroid : public RenderingContextDriverVulkan {
+private:
virtual const char *_get_platform_surface_extension() const override final;
+protected:
+ SurfaceID surface_create(const void *p_platform_data) override final;
+ bool _use_validation_layers() const override final;
+
public:
struct WindowPlatformData {
ANativeWindow *window;
};
- virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
- VulkanContextAndroid() = default;
- ~VulkanContextAndroid() override = default;
-
-protected:
- bool _use_validation_layers() override;
+ RenderingContextDriverVulkanAndroid() = default;
+ ~RenderingContextDriverVulkanAndroid() override = default;
};
#endif // VULKAN_ENABLED
-#endif // VULKAN_CONTEXT_ANDROID_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_ANDROID_H