feat: godot-engine-source-4.3-stable
This commit is contained in:
parent
c59a7dcade
commit
7125d019b5
11149 changed files with 5070401 additions and 0 deletions
21
engine/platform/android/README.md
Normal file
21
engine/platform/android/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Android platform port
|
||||
|
||||
This folder contains the Java and C++ (JNI) code for the Android platform port,
|
||||
using [Gradle](https://gradle.org/) as a build system.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Compiling for Android](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_android.html)
|
||||
- Instructions on building this platform port from source.
|
||||
- [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html)
|
||||
- Instructions on using the compiled export templates to export a project.
|
||||
|
||||
## Artwork license
|
||||
|
||||
[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
|
||||
[Creative Commons Attribution 3.0 Unported](https://developer.android.com/distribute/marketing-tools/brand-guidelines#android_robot)
|
||||
per the Android logo usage guidelines:
|
||||
|
||||
> The Android robot is reproduced or modified from work created and shared by
|
||||
> Google and used according to terms described in the Creative Commons 3.0
|
||||
> Attribution License.
|
||||
114
engine/platform/android/SCsub
Normal file
114
engine/platform/android/SCsub
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from methods import print_warning
|
||||
|
||||
Import("env")
|
||||
|
||||
android_files = [
|
||||
"os_android.cpp",
|
||||
"android_input_handler.cpp",
|
||||
"file_access_android.cpp",
|
||||
"file_access_filesystem_jandroid.cpp",
|
||||
"audio_driver_opensl.cpp",
|
||||
"dir_access_jandroid.cpp",
|
||||
"tts_android.cpp",
|
||||
"thread_jandroid.cpp",
|
||||
"net_socket_android.cpp",
|
||||
"java_godot_lib_jni.cpp",
|
||||
"java_class_wrapper.cpp",
|
||||
"java_godot_wrapper.cpp",
|
||||
"java_godot_view_wrapper.cpp",
|
||||
"java_godot_io_wrapper.cpp",
|
||||
"jni_utils.cpp",
|
||||
"android_keys_utils.cpp",
|
||||
"display_server_android.cpp",
|
||||
"plugin/godot_plugin_jni.cpp",
|
||||
"rendering_context_driver_vulkan_android.cpp",
|
||||
]
|
||||
|
||||
env_android = env.Clone()
|
||||
|
||||
android_objects = []
|
||||
for x in android_files:
|
||||
android_objects.append(env_android.SharedObject(x))
|
||||
|
||||
env_thirdparty = env_android.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
thirdparty_obj = env_thirdparty.SharedObject("#thirdparty/misc/ifaddrs-android.cc")
|
||||
android_objects.append(thirdparty_obj)
|
||||
|
||||
lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
|
||||
|
||||
# Needed to force rebuilding the platform files when the thirdparty code is updated.
|
||||
env.Depends(lib, thirdparty_obj)
|
||||
|
||||
lib_arch_dir = ""
|
||||
if env["arch"] == "arm32":
|
||||
lib_arch_dir = "armeabi-v7a"
|
||||
elif env["arch"] == "arm64":
|
||||
lib_arch_dir = "arm64-v8a"
|
||||
elif env["arch"] == "x86_32":
|
||||
lib_arch_dir = "x86"
|
||||
elif env["arch"] == "x86_64":
|
||||
lib_arch_dir = "x86_64"
|
||||
else:
|
||||
print_warning("Architecture not suitable for embedding into APK; keeping .so at \\bin")
|
||||
|
||||
if lib_arch_dir != "":
|
||||
if env.dev_build:
|
||||
lib_type_dir = "dev"
|
||||
elif env.debug_features:
|
||||
if env.editor_build and env["store_release"]:
|
||||
lib_type_dir = "release"
|
||||
else:
|
||||
lib_type_dir = "debug"
|
||||
else: # Release
|
||||
lib_type_dir = "release"
|
||||
|
||||
if env.editor_build:
|
||||
lib_tools_dir = "tools/"
|
||||
else:
|
||||
lib_tools_dir = ""
|
||||
|
||||
out_dir = "#platform/android/java/lib/libs/" + lib_tools_dir + lib_type_dir + "/" + lib_arch_dir
|
||||
env_android.Command(
|
||||
out_dir + "/libgodot_android.so", "#bin/libgodot" + env["SHLIBSUFFIX"], Move("$TARGET", "$SOURCE")
|
||||
)
|
||||
|
||||
stl_lib_path = (
|
||||
str(env["ANDROID_NDK_ROOT"]) + "/sources/cxx-stl/llvm-libc++/libs/" + lib_arch_dir + "/libc++_shared.so"
|
||||
)
|
||||
env_android.Command(out_dir + "/libc++_shared.so", stl_lib_path, Copy("$TARGET", "$SOURCE"))
|
||||
|
||||
def generate_apk(target, source, env):
|
||||
gradle_process = []
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
gradle_process = [
|
||||
"cmd",
|
||||
"/c",
|
||||
"gradlew.bat",
|
||||
]
|
||||
else:
|
||||
gradle_process = ["./gradlew"]
|
||||
|
||||
gradle_process += [
|
||||
"generateGodotEditor" if env["target"] == "editor" else "generateGodotTemplates",
|
||||
"--quiet",
|
||||
]
|
||||
|
||||
if env["debug_symbols"]:
|
||||
gradle_process += ["-PdoNotStrip=true"]
|
||||
|
||||
subprocess.run(
|
||||
gradle_process,
|
||||
cwd="platform/android/java",
|
||||
)
|
||||
|
||||
if env["generate_apk"]:
|
||||
generate_apk_command = env_android.Command("generate_apk", [], generate_apk)
|
||||
command = env_android.AlwaysBuild(generate_apk_command)
|
||||
env_android.Depends(command, [lib])
|
||||
461
engine/platform/android/android_input_handler.cpp
Normal file
461
engine/platform/android/android_input_handler.cpp
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/**************************************************************************/
|
||||
/* android_input_handler.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "android_input_handler.h"
|
||||
|
||||
#include "android_keys_utils.h"
|
||||
#include "display_server_android.h"
|
||||
|
||||
void AndroidInputHandler::process_joy_event(AndroidInputHandler::JoypadEvent p_event) {
|
||||
switch (p_event.type) {
|
||||
case JOY_EVENT_BUTTON:
|
||||
Input::get_singleton()->joy_button(p_event.device, (JoyButton)p_event.index, p_event.pressed);
|
||||
break;
|
||||
case JOY_EVENT_AXIS:
|
||||
Input::get_singleton()->joy_axis(p_event.device, (JoyAxis)p_event.index, p_event.value);
|
||||
break;
|
||||
case JOY_EVENT_HAT:
|
||||
Input::get_singleton()->joy_hat(p_event.device, p_event.hat);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> ev, Key p_keycode) {
|
||||
if (p_keycode != Key::SHIFT) {
|
||||
ev->set_shift_pressed(shift_mem);
|
||||
}
|
||||
if (p_keycode != Key::ALT) {
|
||||
ev->set_alt_pressed(alt_mem);
|
||||
}
|
||||
if (p_keycode != Key::META) {
|
||||
ev->set_meta_pressed(meta_mem);
|
||||
}
|
||||
if (p_keycode != Key::CTRL) {
|
||||
ev->set_ctrl_pressed(control_mem);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed, bool p_echo) {
|
||||
static char32_t prev_wc = 0;
|
||||
char32_t unicode = p_unicode;
|
||||
if ((p_unicode & 0xfffffc00) == 0xd800) {
|
||||
if (prev_wc != 0) {
|
||||
ERR_PRINT("invalid utf16 surrogate input");
|
||||
}
|
||||
prev_wc = unicode;
|
||||
return; // Skip surrogate.
|
||||
} else if ((unicode & 0xfffffc00) == 0xdc00) {
|
||||
if (prev_wc == 0) {
|
||||
ERR_PRINT("invalid utf16 surrogate input");
|
||||
return; // Skip invalid surrogate.
|
||||
}
|
||||
unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
|
||||
prev_wc = 0;
|
||||
} else {
|
||||
prev_wc = 0;
|
||||
}
|
||||
|
||||
Ref<InputEventKey> ev;
|
||||
ev.instantiate();
|
||||
|
||||
Key physical_keycode = godot_code_from_android_code(p_physical_keycode);
|
||||
Key keycode;
|
||||
if (unicode == '\b') { // 0x08
|
||||
keycode = Key::BACKSPACE;
|
||||
} else if (unicode == '\t') { // 0x09
|
||||
keycode = Key::TAB;
|
||||
} else if (unicode == '\n') { // 0x0A
|
||||
keycode = Key::ENTER;
|
||||
} else if (unicode == 0x1B) {
|
||||
keycode = Key::ESCAPE;
|
||||
} else if (unicode == 0x1F) {
|
||||
keycode = Key::KEY_DELETE;
|
||||
} else {
|
||||
keycode = fix_keycode(unicode, physical_keycode);
|
||||
}
|
||||
|
||||
switch (physical_keycode) {
|
||||
case Key::SHIFT: {
|
||||
shift_mem = p_pressed;
|
||||
} break;
|
||||
case Key::ALT: {
|
||||
alt_mem = p_pressed;
|
||||
} break;
|
||||
case Key::CTRL: {
|
||||
control_mem = p_pressed;
|
||||
} break;
|
||||
case Key::META: {
|
||||
meta_mem = p_pressed;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ev->set_keycode(keycode);
|
||||
ev->set_physical_keycode(physical_keycode);
|
||||
ev->set_key_label(fix_key_label(p_key_label, keycode));
|
||||
ev->set_unicode(fix_unicode(unicode));
|
||||
ev->set_location(godot_location_from_android_code(p_physical_keycode));
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_echo(p_echo);
|
||||
|
||||
_set_key_modifier_state(ev, keycode);
|
||||
|
||||
if (p_physical_keycode == AKEYCODE_BACK) {
|
||||
if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) {
|
||||
dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST, true);
|
||||
}
|
||||
}
|
||||
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_cancel_all_touch() {
|
||||
_parse_all_touch(false, true);
|
||||
touch.clear();
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_parse_all_touch(bool p_pressed, bool p_canceled, bool p_double_tap) {
|
||||
if (touch.size()) {
|
||||
//end all if exist
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
ev.instantiate();
|
||||
ev->set_index(touch[i].id);
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_canceled(p_canceled);
|
||||
ev->set_position(touch[i].pos);
|
||||
ev->set_double_tap(p_double_tap);
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_release_all_touch() {
|
||||
_parse_all_touch(false, false);
|
||||
touch.clear();
|
||||
}
|
||||
|
||||
void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap) {
|
||||
switch (p_event) {
|
||||
case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
|
||||
// Release any remaining touches or mouse event
|
||||
_release_mouse_event_info();
|
||||
_release_all_touch();
|
||||
|
||||
touch.resize(p_points.size());
|
||||
for (int i = 0; i < p_points.size(); i++) {
|
||||
touch.write[i].id = p_points[i].id;
|
||||
touch.write[i].pos = p_points[i].pos;
|
||||
touch.write[i].pressure = p_points[i].pressure;
|
||||
touch.write[i].tilt = p_points[i].tilt;
|
||||
}
|
||||
|
||||
//send touch
|
||||
_parse_all_touch(true, false, p_double_tap);
|
||||
|
||||
} break;
|
||||
case AMOTION_EVENT_ACTION_MOVE: { //motion
|
||||
if (touch.size() != p_points.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
int idx = -1;
|
||||
for (int j = 0; j < p_points.size(); j++) {
|
||||
if (touch[i].id == p_points[j].id) {
|
||||
idx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_CONTINUE(idx == -1);
|
||||
|
||||
if (touch[i].pos == p_points[idx].pos) {
|
||||
continue; // Don't move unnecessarily.
|
||||
}
|
||||
|
||||
Ref<InputEventScreenDrag> ev;
|
||||
ev.instantiate();
|
||||
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());
|
||||
ev->set_pressure(p_points[idx].pressure);
|
||||
ev->set_tilt(p_points[idx].tilt);
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
touch.write[i].pos = p_points[idx].pos;
|
||||
}
|
||||
|
||||
} break;
|
||||
case AMOTION_EVENT_ACTION_CANCEL: {
|
||||
_cancel_all_touch();
|
||||
} break;
|
||||
case AMOTION_EVENT_ACTION_UP: { //release
|
||||
_release_all_touch();
|
||||
} break;
|
||||
case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch
|
||||
for (int i = 0; i < p_points.size(); i++) {
|
||||
if (p_points[i].id == p_pointer) {
|
||||
TouchPos tp = p_points[i];
|
||||
touch.push_back(tp);
|
||||
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
ev.instantiate();
|
||||
|
||||
ev->set_index(tp.id);
|
||||
ev->set_pressed(true);
|
||||
ev->set_position(tp.pos);
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case AMOTION_EVENT_ACTION_POINTER_UP: { // remove touch
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
if (touch[i].id == p_pointer) {
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
ev.instantiate();
|
||||
ev->set_index(touch[i].id);
|
||||
ev->set_pressed(false);
|
||||
ev->set_position(touch[i].pos);
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
touch.remove_at(i);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_cancel_mouse_event_info(bool p_source_mouse_relative) {
|
||||
buttons_state = BitField<MouseButtonMask>();
|
||||
_parse_mouse_event_info(BitField<MouseButtonMask>(), false, true, false, p_source_mouse_relative);
|
||||
mouse_event_info.valid = false;
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_parse_mouse_event_info(BitField<MouseButtonMask> event_buttons_mask, bool p_pressed, bool p_canceled, bool p_double_click, bool p_source_mouse_relative) {
|
||||
if (!mouse_event_info.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> ev;
|
||||
ev.instantiate();
|
||||
_set_key_modifier_state(ev, Key::NONE);
|
||||
if (p_source_mouse_relative) {
|
||||
ev->set_position(hover_prev_pos);
|
||||
ev->set_global_position(hover_prev_pos);
|
||||
} else {
|
||||
ev->set_position(mouse_event_info.pos);
|
||||
ev->set_global_position(mouse_event_info.pos);
|
||||
hover_prev_pos = mouse_event_info.pos;
|
||||
}
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_canceled(p_canceled);
|
||||
BitField<MouseButtonMask> changed_button_mask = BitField<MouseButtonMask>(buttons_state.operator int64_t() ^ event_buttons_mask.operator int64_t());
|
||||
|
||||
buttons_state = event_buttons_mask;
|
||||
|
||||
ev->set_button_index(_button_index_from_mask(changed_button_mask));
|
||||
ev->set_button_mask(event_buttons_mask);
|
||||
ev->set_double_click(p_double_click);
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) {
|
||||
_parse_mouse_event_info(BitField<MouseButtonMask>(), false, false, false, p_source_mouse_relative);
|
||||
mouse_event_info.valid = false;
|
||||
}
|
||||
|
||||
void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative, float p_pressure, Vector2 p_tilt) {
|
||||
BitField<MouseButtonMask> event_buttons_mask = _android_button_mask_to_godot_button_mask(p_event_android_buttons_mask);
|
||||
switch (p_event_action) {
|
||||
case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
|
||||
case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter
|
||||
case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit
|
||||
// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
|
||||
Ref<InputEventMouseMotion> ev;
|
||||
ev.instantiate();
|
||||
_set_key_modifier_state(ev, Key::NONE);
|
||||
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;
|
||||
|
||||
case AMOTION_EVENT_ACTION_DOWN:
|
||||
case AMOTION_EVENT_ACTION_BUTTON_PRESS: {
|
||||
// Release any remaining touches or mouse event
|
||||
_release_mouse_event_info();
|
||||
_release_all_touch();
|
||||
|
||||
mouse_event_info.valid = true;
|
||||
mouse_event_info.pos = p_event_pos;
|
||||
_parse_mouse_event_info(event_buttons_mask, true, false, p_double_click, p_source_mouse_relative);
|
||||
} break;
|
||||
|
||||
case AMOTION_EVENT_ACTION_CANCEL: {
|
||||
_cancel_mouse_event_info(p_source_mouse_relative);
|
||||
} break;
|
||||
|
||||
case AMOTION_EVENT_ACTION_UP:
|
||||
case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
|
||||
_release_mouse_event_info(p_source_mouse_relative);
|
||||
} break;
|
||||
|
||||
case AMOTION_EVENT_ACTION_MOVE: {
|
||||
if (!mouse_event_info.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> ev;
|
||||
ev.instantiate();
|
||||
_set_key_modifier_state(ev, Key::NONE);
|
||||
if (p_source_mouse_relative) {
|
||||
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;
|
||||
}
|
||||
ev->set_button_mask(event_buttons_mask);
|
||||
ev->set_pressure(p_pressure);
|
||||
ev->set_tilt(p_tilt);
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
} break;
|
||||
|
||||
case AMOTION_EVENT_ACTION_SCROLL: {
|
||||
Ref<InputEventMouseButton> ev;
|
||||
ev.instantiate();
|
||||
_set_key_modifier_state(ev, Key::NONE);
|
||||
if (p_source_mouse_relative) {
|
||||
ev->set_position(hover_prev_pos);
|
||||
ev->set_global_position(hover_prev_pos);
|
||||
} else {
|
||||
ev->set_position(p_event_pos);
|
||||
ev->set_global_position(p_event_pos);
|
||||
}
|
||||
ev->set_pressed(true);
|
||||
buttons_state = event_buttons_mask;
|
||||
if (p_delta.y > 0) {
|
||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, p_delta.y);
|
||||
} else if (p_delta.y < 0) {
|
||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -p_delta.y);
|
||||
}
|
||||
|
||||
if (p_delta.x > 0) {
|
||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, p_delta.x);
|
||||
} else if (p_delta.x < 0) {
|
||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -p_delta.x);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidInputHandler::_wheel_button_click(BitField<MouseButtonMask> event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor) {
|
||||
Ref<InputEventMouseButton> evd = ev->duplicate();
|
||||
_set_key_modifier_state(evd, Key::NONE);
|
||||
evd->set_button_index(wheel_button);
|
||||
evd->set_button_mask(BitField<MouseButtonMask>(event_buttons_mask.operator int64_t() ^ int64_t(mouse_button_to_mask(wheel_button))));
|
||||
evd->set_factor(factor);
|
||||
Input::get_singleton()->parse_input_event(evd);
|
||||
Ref<InputEventMouseButton> evdd = evd->duplicate();
|
||||
evdd->set_pressed(false);
|
||||
evdd->set_button_mask(event_buttons_mask);
|
||||
Input::get_singleton()->parse_input_event(evdd);
|
||||
}
|
||||
|
||||
void AndroidInputHandler::process_magnify(Point2 p_pos, float p_factor) {
|
||||
Ref<InputEventMagnifyGesture> magnify_event;
|
||||
magnify_event.instantiate();
|
||||
_set_key_modifier_state(magnify_event, Key::NONE);
|
||||
magnify_event->set_position(p_pos);
|
||||
magnify_event->set_factor(p_factor);
|
||||
Input::get_singleton()->parse_input_event(magnify_event);
|
||||
}
|
||||
|
||||
void AndroidInputHandler::process_pan(Point2 p_pos, Vector2 p_delta) {
|
||||
Ref<InputEventPanGesture> pan_event;
|
||||
pan_event.instantiate();
|
||||
_set_key_modifier_state(pan_event, Key::NONE);
|
||||
pan_event->set_position(p_pos);
|
||||
pan_event->set_delta(p_delta);
|
||||
Input::get_singleton()->parse_input_event(pan_event);
|
||||
}
|
||||
|
||||
MouseButton AndroidInputHandler::_button_index_from_mask(BitField<MouseButtonMask> button_mask) {
|
||||
switch (MouseButtonMask(button_mask.operator int64_t())) {
|
||||
case MouseButtonMask::LEFT:
|
||||
return MouseButton::LEFT;
|
||||
case MouseButtonMask::RIGHT:
|
||||
return MouseButton::RIGHT;
|
||||
case MouseButtonMask::MIDDLE:
|
||||
return MouseButton::MIDDLE;
|
||||
case MouseButtonMask::MB_XBUTTON1:
|
||||
return MouseButton::MB_XBUTTON1;
|
||||
case MouseButtonMask::MB_XBUTTON2:
|
||||
return MouseButton::MB_XBUTTON2;
|
||||
default:
|
||||
return MouseButton::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
BitField<MouseButtonMask> AndroidInputHandler::_android_button_mask_to_godot_button_mask(int android_button_mask) {
|
||||
BitField<MouseButtonMask> godot_button_mask;
|
||||
if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {
|
||||
godot_button_mask.set_flag(MouseButtonMask::LEFT);
|
||||
}
|
||||
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
|
||||
godot_button_mask.set_flag(MouseButtonMask::RIGHT);
|
||||
}
|
||||
if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {
|
||||
godot_button_mask.set_flag(MouseButtonMask::MIDDLE);
|
||||
}
|
||||
if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
|
||||
godot_button_mask.set_flag(MouseButtonMask::MB_XBUTTON1);
|
||||
}
|
||||
if (android_button_mask & AMOTION_EVENT_BUTTON_FORWARD) {
|
||||
godot_button_mask.set_flag(MouseButtonMask::MB_XBUTTON2);
|
||||
}
|
||||
|
||||
return godot_button_mask;
|
||||
}
|
||||
109
engine/platform/android/android_input_handler.h
Normal file
109
engine/platform/android/android_input_handler.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/**************************************************************************/
|
||||
/* android_input_handler.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_INPUT_HANDLER_H
|
||||
#define ANDROID_INPUT_HANDLER_H
|
||||
|
||||
#include "core/input/input.h"
|
||||
|
||||
// This class encapsulates all the handling of input events that come from the Android UI thread.
|
||||
// Remarks:
|
||||
// - It's not thread-safe by itself, so its functions must only be called on a single thread, which is the Android UI thread.
|
||||
// - Its functions must only call thread-safe methods.
|
||||
class AndroidInputHandler {
|
||||
public:
|
||||
struct TouchPos {
|
||||
int id = 0;
|
||||
Point2 pos;
|
||||
float pressure = 0;
|
||||
Vector2 tilt;
|
||||
};
|
||||
|
||||
struct MouseEventInfo {
|
||||
bool valid = false;
|
||||
Point2 pos;
|
||||
};
|
||||
|
||||
enum {
|
||||
JOY_EVENT_BUTTON = 0,
|
||||
JOY_EVENT_AXIS = 1,
|
||||
JOY_EVENT_HAT = 2
|
||||
};
|
||||
|
||||
struct JoypadEvent {
|
||||
int device = 0;
|
||||
int type = 0;
|
||||
int index = 0; // Can be either JoyAxis or JoyButton.
|
||||
bool pressed = false;
|
||||
float value = 0;
|
||||
BitField<HatMask> hat;
|
||||
};
|
||||
|
||||
private:
|
||||
bool alt_mem = false;
|
||||
bool shift_mem = false;
|
||||
bool control_mem = false;
|
||||
bool meta_mem = false;
|
||||
|
||||
BitField<MouseButtonMask> buttons_state;
|
||||
|
||||
Vector<TouchPos> touch;
|
||||
MouseEventInfo mouse_event_info;
|
||||
Point2 hover_prev_pos; // needed to calculate the relative position on hover events
|
||||
|
||||
void _set_key_modifier_state(Ref<InputEventWithModifiers> ev, Key p_keycode);
|
||||
|
||||
static MouseButton _button_index_from_mask(BitField<MouseButtonMask> button_mask);
|
||||
static BitField<MouseButtonMask> _android_button_mask_to_godot_button_mask(int android_button_mask);
|
||||
|
||||
void _wheel_button_click(BitField<MouseButtonMask> event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor);
|
||||
|
||||
void _parse_mouse_event_info(BitField<MouseButtonMask> event_buttons_mask, bool p_pressed, bool p_canceled, bool p_double_click, bool p_source_mouse_relative);
|
||||
|
||||
void _release_mouse_event_info(bool p_source_mouse_relative = false);
|
||||
|
||||
void _cancel_mouse_event_info(bool p_source_mouse_relative = false);
|
||||
|
||||
void _parse_all_touch(bool p_pressed, bool p_canceled = false, bool p_double_tap = false);
|
||||
|
||||
void _release_all_touch();
|
||||
|
||||
void _cancel_all_touch();
|
||||
|
||||
public:
|
||||
void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative, float p_pressure, Vector2 p_tilt);
|
||||
void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap);
|
||||
void process_magnify(Point2 p_pos, float p_factor);
|
||||
void process_pan(Point2 p_pos, Vector2 p_delta);
|
||||
void process_joy_event(JoypadEvent p_event);
|
||||
void process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed, bool p_echo);
|
||||
};
|
||||
|
||||
#endif // ANDROID_INPUT_HANDLER_H
|
||||
49
engine/platform/android/android_keys_utils.cpp
Normal file
49
engine/platform/android/android_keys_utils.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**************************************************************************/
|
||||
/* android_keys_utils.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "android_keys_utils.h"
|
||||
|
||||
Key godot_code_from_android_code(unsigned int p_code) {
|
||||
for (int i = 0; android_godot_code_pairs[i].android_code != AKEYCODE_MAX; i++) {
|
||||
if (android_godot_code_pairs[i].android_code == p_code) {
|
||||
return android_godot_code_pairs[i].godot_code;
|
||||
}
|
||||
}
|
||||
return Key::UNKNOWN;
|
||||
}
|
||||
|
||||
KeyLocation godot_location_from_android_code(unsigned int p_code) {
|
||||
for (int i = 0; android_godot_location_pairs[i].android_code != AKEYCODE_MAX; i++) {
|
||||
if (android_godot_location_pairs[i].android_code == p_code) {
|
||||
return android_godot_location_pairs[i].godot_code;
|
||||
}
|
||||
}
|
||||
return KeyLocation::UNSPECIFIED;
|
||||
}
|
||||
200
engine/platform/android/android_keys_utils.h
Normal file
200
engine/platform/android/android_keys_utils.h
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
/**************************************************************************/
|
||||
/* android_keys_utils.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_KEYS_UTILS_H
|
||||
#define ANDROID_KEYS_UTILS_H
|
||||
|
||||
#include "core/os/keyboard.h"
|
||||
|
||||
#include <android/input.h>
|
||||
|
||||
#define AKEYCODE_MAX 0xFFFF
|
||||
|
||||
struct AndroidGodotCodePair {
|
||||
unsigned int android_code = 0;
|
||||
Key godot_code = Key::NONE;
|
||||
};
|
||||
|
||||
static AndroidGodotCodePair android_godot_code_pairs[] = {
|
||||
{ AKEYCODE_UNKNOWN, Key::UNKNOWN }, // (0) Unknown key code.
|
||||
{ AKEYCODE_BACK, Key::BACK }, // (4) Back key.
|
||||
{ AKEYCODE_0, Key::KEY_0 }, // (7) '0' key.
|
||||
{ AKEYCODE_1, Key::KEY_1 }, // (8) '1' key.
|
||||
{ AKEYCODE_2, Key::KEY_2 }, // (9) '2' key.
|
||||
{ AKEYCODE_3, Key::KEY_3 }, // (10) '3' key.
|
||||
{ AKEYCODE_4, Key::KEY_4 }, // (11) '4' key.
|
||||
{ AKEYCODE_5, Key::KEY_5 }, // (12) '5' key.
|
||||
{ AKEYCODE_6, Key::KEY_6 }, // (13) '6' key.
|
||||
{ AKEYCODE_7, Key::KEY_7 }, // (14) '7' key.
|
||||
{ AKEYCODE_8, Key::KEY_8 }, // (15) '8' key.
|
||||
{ AKEYCODE_9, Key::KEY_9 }, // (16) '9' key.
|
||||
{ AKEYCODE_STAR, Key::ASTERISK }, // (17) '*' key.
|
||||
{ AKEYCODE_POUND, Key::NUMBERSIGN }, // (18) '#' key.
|
||||
{ AKEYCODE_DPAD_UP, Key::UP }, // (19) Directional Pad Up key.
|
||||
{ AKEYCODE_DPAD_DOWN, Key::DOWN }, // (20) Directional Pad Down key.
|
||||
{ AKEYCODE_DPAD_LEFT, Key::LEFT }, // (21) Directional Pad Left key.
|
||||
{ AKEYCODE_DPAD_RIGHT, Key::RIGHT }, // (22) Directional Pad Right key.
|
||||
{ AKEYCODE_DPAD_CENTER, Key::ENTER }, // (23) Directional Pad Center key.
|
||||
{ AKEYCODE_VOLUME_UP, Key::VOLUMEUP }, // (24) Volume Up key.
|
||||
{ AKEYCODE_VOLUME_DOWN, Key::VOLUMEDOWN }, // (25) Volume Down key.
|
||||
{ AKEYCODE_POWER, Key::STANDBY }, // (26) Power key.
|
||||
{ AKEYCODE_CLEAR, Key::CLEAR }, // (28) Clear key.
|
||||
{ AKEYCODE_A, Key::A }, // (29) 'A' key.
|
||||
{ AKEYCODE_B, Key::B }, // (30) 'B' key.
|
||||
{ AKEYCODE_C, Key::C }, // (31) 'C' key.
|
||||
{ AKEYCODE_D, Key::D }, // (32) 'D' key.
|
||||
{ AKEYCODE_E, Key::E }, // (33) 'E' key.
|
||||
{ AKEYCODE_F, Key::F }, // (34) 'F' key.
|
||||
{ AKEYCODE_G, Key::G }, // (35) 'G' key.
|
||||
{ AKEYCODE_H, Key::H }, // (36) 'H' key.
|
||||
{ AKEYCODE_I, Key::I }, // (37) 'I' key.
|
||||
{ AKEYCODE_J, Key::J }, // (38) 'J' key.
|
||||
{ AKEYCODE_K, Key::K }, // (39) 'K' key.
|
||||
{ AKEYCODE_L, Key::L }, // (40) 'L' key.
|
||||
{ AKEYCODE_M, Key::M }, // (41) 'M' key.
|
||||
{ AKEYCODE_N, Key::N }, // (42) 'N' key.
|
||||
{ AKEYCODE_O, Key::O }, // (43) 'O' key.
|
||||
{ AKEYCODE_P, Key::P }, // (44) 'P' key.
|
||||
{ AKEYCODE_Q, Key::Q }, // (45) 'Q' key.
|
||||
{ AKEYCODE_R, Key::R }, // (46) 'R' key.
|
||||
{ AKEYCODE_S, Key::S }, // (47) 'S' key.
|
||||
{ AKEYCODE_T, Key::T }, // (48) 'T' key.
|
||||
{ AKEYCODE_U, Key::U }, // (49) 'U' key.
|
||||
{ AKEYCODE_V, Key::V }, // (50) 'V' key.
|
||||
{ AKEYCODE_W, Key::W }, // (51) 'W' key.
|
||||
{ AKEYCODE_X, Key::X }, // (52) 'X' key.
|
||||
{ AKEYCODE_Y, Key::Y }, // (53) 'Y' key.
|
||||
{ AKEYCODE_Z, Key::Z }, // (54) 'Z' key.
|
||||
{ AKEYCODE_COMMA, Key::COMMA }, // (55) ',’ key.
|
||||
{ AKEYCODE_PERIOD, Key::PERIOD }, // (56) '.' key.
|
||||
{ AKEYCODE_ALT_LEFT, Key::ALT }, // (57) Left Alt modifier key.
|
||||
{ AKEYCODE_ALT_RIGHT, Key::ALT }, // (58) Right Alt modifier key.
|
||||
{ AKEYCODE_SHIFT_LEFT, Key::SHIFT }, // (59) Left Shift modifier key.
|
||||
{ AKEYCODE_SHIFT_RIGHT, Key::SHIFT }, // (60) Right Shift modifier key.
|
||||
{ AKEYCODE_TAB, Key::TAB }, // (61) Tab key.
|
||||
{ AKEYCODE_SPACE, Key::SPACE }, // (62) Space key.
|
||||
{ AKEYCODE_ENVELOPE, Key::LAUNCHMAIL }, // (65) Envelope special function key.
|
||||
{ AKEYCODE_ENTER, Key::ENTER }, // (66) Enter key.
|
||||
{ AKEYCODE_DEL, Key::BACKSPACE }, // (67) Backspace key.
|
||||
{ AKEYCODE_GRAVE, Key::QUOTELEFT }, // (68) '`' (backtick) key.
|
||||
{ AKEYCODE_MINUS, Key::MINUS }, // (69) '-'.
|
||||
{ AKEYCODE_EQUALS, Key::EQUAL }, // (70) '=' key.
|
||||
{ AKEYCODE_LEFT_BRACKET, Key::BRACKETLEFT }, // (71) '[' key.
|
||||
{ AKEYCODE_RIGHT_BRACKET, Key::BRACKETRIGHT }, // (72) ']' key.
|
||||
{ AKEYCODE_BACKSLASH, Key::BACKSLASH }, // (73) '\' key.
|
||||
{ AKEYCODE_SEMICOLON, Key::SEMICOLON }, // (74) ';' key.
|
||||
{ AKEYCODE_APOSTROPHE, Key::APOSTROPHE }, // (75) ''' (apostrophe) key.
|
||||
{ AKEYCODE_SLASH, Key::SLASH }, // (76) '/' key.
|
||||
{ AKEYCODE_AT, Key::AT }, // (77) '@' key.
|
||||
{ AKEYCODE_PLUS, Key::PLUS }, // (81) '+' key.
|
||||
{ AKEYCODE_MENU, Key::MENU }, // (82) Menu key.
|
||||
{ AKEYCODE_SEARCH, Key::SEARCH }, // (84) Search key.
|
||||
{ AKEYCODE_MEDIA_STOP, Key::MEDIASTOP }, // (86) Stop media key.
|
||||
{ AKEYCODE_MEDIA_NEXT, Key::MEDIANEXT }, // (87) Play Next media key.
|
||||
{ AKEYCODE_MEDIA_PREVIOUS, Key::MEDIAPREVIOUS }, // (88) Play Previous media key.
|
||||
{ AKEYCODE_PAGE_UP, Key::PAGEUP }, // (92) Page Up key.
|
||||
{ AKEYCODE_PAGE_DOWN, Key::PAGEDOWN }, // (93) Page Down key.
|
||||
{ AKEYCODE_ESCAPE, Key::ESCAPE }, // (111) Escape key.
|
||||
{ AKEYCODE_FORWARD_DEL, Key::KEY_DELETE }, // (112) Forward Delete key.
|
||||
{ AKEYCODE_CTRL_LEFT, Key::CTRL }, // (113) Left Control modifier key.
|
||||
{ AKEYCODE_CTRL_RIGHT, Key::CTRL }, // (114) Right Control modifier key.
|
||||
{ AKEYCODE_CAPS_LOCK, Key::CAPSLOCK }, // (115) Caps Lock key.
|
||||
{ AKEYCODE_SCROLL_LOCK, Key::SCROLLLOCK }, // (116) Scroll Lock key.
|
||||
{ AKEYCODE_META_LEFT, Key::META }, // (117) Left Meta modifier key.
|
||||
{ AKEYCODE_META_RIGHT, Key::META }, // (118) Right Meta modifier key.
|
||||
{ AKEYCODE_SYSRQ, Key::PRINT }, // (120) System Request / Print Screen key.
|
||||
{ AKEYCODE_BREAK, Key::PAUSE }, // (121) Break / Pause key.
|
||||
{ AKEYCODE_MOVE_HOME, Key::HOME }, // (122) Home Movement key.
|
||||
{ AKEYCODE_MOVE_END, Key::END }, // (123) End Movement key.
|
||||
{ AKEYCODE_INSERT, Key::INSERT }, // (124) Insert key.
|
||||
{ AKEYCODE_FORWARD, Key::FORWARD }, // (125) Forward key.
|
||||
{ AKEYCODE_MEDIA_PLAY, Key::MEDIAPLAY }, // (126) Play media key.
|
||||
{ AKEYCODE_MEDIA_RECORD, Key::MEDIARECORD }, // (130) Record media key.
|
||||
{ AKEYCODE_F1, Key::F1 }, // (131) F1 key.
|
||||
{ AKEYCODE_F2, Key::F2 }, // (132) F2 key.
|
||||
{ AKEYCODE_F3, Key::F3 }, // (133) F3 key.
|
||||
{ AKEYCODE_F4, Key::F4 }, // (134) F4 key.
|
||||
{ AKEYCODE_F5, Key::F5 }, // (135) F5 key.
|
||||
{ AKEYCODE_F6, Key::F6 }, // (136) F6 key.
|
||||
{ AKEYCODE_F7, Key::F7 }, // (137) F7 key.
|
||||
{ AKEYCODE_F8, Key::F8 }, // (138) F8 key.
|
||||
{ AKEYCODE_F9, Key::F9 }, // (139) F9 key.
|
||||
{ AKEYCODE_F10, Key::F10 }, // (140) F10 key.
|
||||
{ AKEYCODE_F11, Key::F11 }, // (141) F11 key.
|
||||
{ AKEYCODE_F12, Key::F12 }, // (142) F12 key.
|
||||
{ AKEYCODE_NUM_LOCK, Key::NUMLOCK }, // (143) Num Lock key.
|
||||
{ AKEYCODE_NUMPAD_0, Key::KP_0 }, // (144) Numeric keypad '0' key.
|
||||
{ AKEYCODE_NUMPAD_1, Key::KP_1 }, // (145) Numeric keypad '1' key.
|
||||
{ AKEYCODE_NUMPAD_2, Key::KP_2 }, // (146) Numeric keypad '2' key.
|
||||
{ AKEYCODE_NUMPAD_3, Key::KP_3 }, // (147) Numeric keypad '3' key.
|
||||
{ AKEYCODE_NUMPAD_4, Key::KP_4 }, // (148) Numeric keypad '4' key.
|
||||
{ AKEYCODE_NUMPAD_5, Key::KP_5 }, // (149) Numeric keypad '5' key.
|
||||
{ AKEYCODE_NUMPAD_6, Key::KP_6 }, // (150) Numeric keypad '6' key.
|
||||
{ AKEYCODE_NUMPAD_7, Key::KP_7 }, // (151) Numeric keypad '7' key.
|
||||
{ AKEYCODE_NUMPAD_8, Key::KP_8 }, // (152) Numeric keypad '8' key.
|
||||
{ AKEYCODE_NUMPAD_9, Key::KP_9 }, // (153) Numeric keypad '9' key.
|
||||
{ AKEYCODE_NUMPAD_DIVIDE, Key::KP_DIVIDE }, // (154) Numeric keypad '/' key (for division).
|
||||
{ AKEYCODE_NUMPAD_MULTIPLY, Key::KP_MULTIPLY }, // (155) Numeric keypad '*' key (for multiplication).
|
||||
{ AKEYCODE_NUMPAD_SUBTRACT, Key::KP_SUBTRACT }, // (156) Numeric keypad '-' key (for subtraction).
|
||||
{ AKEYCODE_NUMPAD_ADD, Key::KP_ADD }, // (157) Numeric keypad '+' key (for addition).
|
||||
{ AKEYCODE_NUMPAD_DOT, Key::KP_PERIOD }, // (158) Numeric keypad '.' key (for decimals or digit grouping).
|
||||
{ AKEYCODE_NUMPAD_ENTER, Key::KP_ENTER }, // (160) Numeric keypad Enter key.
|
||||
{ AKEYCODE_VOLUME_MUTE, Key::VOLUMEMUTE }, // (164) Volume Mute key.
|
||||
{ AKEYCODE_EISU, Key::JIS_EISU }, // (212) JIS EISU key.
|
||||
{ AKEYCODE_YEN, Key::YEN }, // (216) Japanese Yen key.
|
||||
{ AKEYCODE_KANA, Key::JIS_KANA }, // (218) JIS KANA key.
|
||||
{ AKEYCODE_HELP, Key::HELP }, // (259) Help key.
|
||||
{ AKEYCODE_REFRESH, Key::REFRESH }, // (285) Refresh key.
|
||||
{ AKEYCODE_MAX, Key::UNKNOWN }
|
||||
};
|
||||
|
||||
Key godot_code_from_android_code(unsigned int p_code);
|
||||
|
||||
// Key location determination.
|
||||
struct AndroidGodotLocationPair {
|
||||
unsigned int android_code = 0;
|
||||
KeyLocation godot_code = KeyLocation::UNSPECIFIED;
|
||||
};
|
||||
|
||||
static AndroidGodotLocationPair android_godot_location_pairs[] = {
|
||||
{ AKEYCODE_ALT_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_ALT_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_SHIFT_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_SHIFT_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_CTRL_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_CTRL_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_META_LEFT, KeyLocation::LEFT },
|
||||
{ AKEYCODE_META_RIGHT, KeyLocation::RIGHT },
|
||||
{ AKEYCODE_MAX, KeyLocation::UNSPECIFIED }
|
||||
};
|
||||
|
||||
KeyLocation godot_location_from_android_code(unsigned int p_code);
|
||||
|
||||
#endif // ANDROID_KEYS_UTILS_H
|
||||
89
engine/platform/android/api/api.cpp
Normal file
89
engine/platform/android/api/api.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**************************************************************************/
|
||||
/* api.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#include "java_class_wrapper.h"
|
||||
#include "jni_singleton.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
|
||||
#if !defined(ANDROID_ENABLED)
|
||||
static JavaClassWrapper *java_class_wrapper = nullptr;
|
||||
#endif
|
||||
|
||||
void register_android_api() {
|
||||
#if !defined(ANDROID_ENABLED)
|
||||
// On Android platforms, the `java_class_wrapper` instantiation and the
|
||||
// `JNISingleton` registration occurs in
|
||||
// `platform/android/java_godot_lib_jni.cpp#Java_org_godotengine_godot_GodotLib_setup`
|
||||
java_class_wrapper = memnew(JavaClassWrapper); // Dummy
|
||||
GDREGISTER_CLASS(JNISingleton);
|
||||
#endif
|
||||
|
||||
GDREGISTER_CLASS(JavaClass);
|
||||
GDREGISTER_CLASS(JavaClassWrapper);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("JavaClassWrapper", JavaClassWrapper::get_singleton()));
|
||||
}
|
||||
|
||||
void unregister_android_api() {
|
||||
#if !defined(ANDROID_ENABLED)
|
||||
memdelete(java_class_wrapper);
|
||||
#endif
|
||||
}
|
||||
|
||||
void JavaClassWrapper::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("wrap", "name"), &JavaClassWrapper::wrap);
|
||||
}
|
||||
|
||||
#if !defined(ANDROID_ENABLED)
|
||||
|
||||
Variant JavaClass::callp(const StringName &, const Variant **, int, Callable::CallError &) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
JavaClass::JavaClass() {
|
||||
}
|
||||
|
||||
Variant JavaObject::callp(const StringName &, const Variant **, int, Callable::CallError &) {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
|
||||
|
||||
Ref<JavaClass> JavaClassWrapper::wrap(const String &) {
|
||||
return Ref<JavaClass>();
|
||||
}
|
||||
|
||||
JavaClassWrapper::JavaClassWrapper() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
#endif
|
||||
37
engine/platform/android/api/api.h
Normal file
37
engine/platform/android/api/api.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/**************************************************************************/
|
||||
/* api.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_API_H
|
||||
#define ANDROID_API_H
|
||||
|
||||
void register_android_api();
|
||||
void unregister_android_api();
|
||||
|
||||
#endif // ANDROID_API_H
|
||||
251
engine/platform/android/api/java_class_wrapper.h
Normal file
251
engine/platform/android/api/java_class_wrapper.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/**************************************************************************/
|
||||
/* java_class_wrapper.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef JAVA_CLASS_WRAPPER_H
|
||||
#define JAVA_CLASS_WRAPPER_H
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
class JavaObject;
|
||||
#endif
|
||||
|
||||
class JavaClass : public RefCounted {
|
||||
GDCLASS(JavaClass, RefCounted);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
enum ArgumentType{
|
||||
ARG_TYPE_VOID,
|
||||
ARG_TYPE_BOOLEAN,
|
||||
ARG_TYPE_BYTE,
|
||||
ARG_TYPE_CHAR,
|
||||
ARG_TYPE_SHORT,
|
||||
ARG_TYPE_INT,
|
||||
ARG_TYPE_LONG,
|
||||
ARG_TYPE_FLOAT,
|
||||
ARG_TYPE_DOUBLE,
|
||||
ARG_TYPE_STRING, //special case
|
||||
ARG_TYPE_CLASS,
|
||||
ARG_ARRAY_BIT = 1 << 16,
|
||||
ARG_NUMBER_CLASS_BIT = 1 << 17,
|
||||
ARG_TYPE_MASK = (1 << 16) - 1
|
||||
};
|
||||
|
||||
RBMap<StringName, Variant> constant_map;
|
||||
|
||||
struct MethodInfo {
|
||||
bool _static = false;
|
||||
Vector<uint32_t> param_types;
|
||||
Vector<StringName> param_sigs;
|
||||
uint32_t return_type = 0;
|
||||
jmethodID method;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ static void _convert_to_variant_type(int p_sig, Variant::Type &r_type, float &likelihood) {
|
||||
likelihood = 1.0;
|
||||
r_type = Variant::NIL;
|
||||
|
||||
switch (p_sig) {
|
||||
case ARG_TYPE_VOID:
|
||||
r_type = Variant::NIL;
|
||||
break;
|
||||
case ARG_TYPE_BOOLEAN | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_BOOLEAN:
|
||||
r_type = Variant::BOOL;
|
||||
break;
|
||||
case ARG_TYPE_BYTE | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_BYTE:
|
||||
r_type = Variant::INT;
|
||||
likelihood = 0.1;
|
||||
break;
|
||||
case ARG_TYPE_CHAR | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_CHAR:
|
||||
r_type = Variant::INT;
|
||||
likelihood = 0.2;
|
||||
break;
|
||||
case ARG_TYPE_SHORT | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_SHORT:
|
||||
r_type = Variant::INT;
|
||||
likelihood = 0.3;
|
||||
break;
|
||||
case ARG_TYPE_INT | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_INT:
|
||||
r_type = Variant::INT;
|
||||
likelihood = 1.0;
|
||||
break;
|
||||
case ARG_TYPE_LONG | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_LONG:
|
||||
r_type = Variant::INT;
|
||||
likelihood = 0.5;
|
||||
break;
|
||||
case ARG_TYPE_FLOAT | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_FLOAT:
|
||||
r_type = Variant::FLOAT;
|
||||
likelihood = 1.0;
|
||||
break;
|
||||
case ARG_TYPE_DOUBLE | ARG_NUMBER_CLASS_BIT:
|
||||
case ARG_TYPE_DOUBLE:
|
||||
r_type = Variant::FLOAT;
|
||||
likelihood = 0.5;
|
||||
break;
|
||||
case ARG_TYPE_STRING:
|
||||
r_type = Variant::STRING;
|
||||
break;
|
||||
case ARG_TYPE_CLASS:
|
||||
r_type = Variant::OBJECT;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_VOID:
|
||||
r_type = Variant::NIL;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN:
|
||||
r_type = Variant::ARRAY;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_BYTE:
|
||||
r_type = Variant::PACKED_BYTE_ARRAY;
|
||||
likelihood = 1.0;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_CHAR:
|
||||
r_type = Variant::PACKED_BYTE_ARRAY;
|
||||
likelihood = 0.5;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_SHORT:
|
||||
r_type = Variant::PACKED_INT32_ARRAY;
|
||||
likelihood = 0.3;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_INT:
|
||||
r_type = Variant::PACKED_INT32_ARRAY;
|
||||
likelihood = 1.0;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_LONG:
|
||||
r_type = Variant::PACKED_INT32_ARRAY;
|
||||
likelihood = 0.5;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_FLOAT:
|
||||
r_type = Variant::PACKED_FLOAT32_ARRAY;
|
||||
likelihood = 1.0;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE:
|
||||
r_type = Variant::PACKED_FLOAT32_ARRAY;
|
||||
likelihood = 0.5;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_STRING:
|
||||
r_type = Variant::PACKED_STRING_ARRAY;
|
||||
break;
|
||||
case ARG_ARRAY_BIT | ARG_TYPE_CLASS:
|
||||
r_type = Variant::ARRAY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static bool _convert_object_to_variant(JNIEnv *env, jobject obj, Variant &var, uint32_t p_sig);
|
||||
|
||||
bool _call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret);
|
||||
|
||||
friend class JavaClassWrapper;
|
||||
HashMap<StringName, List<MethodInfo>> methods;
|
||||
jclass _class;
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
|
||||
|
||||
JavaClass();
|
||||
};
|
||||
|
||||
class JavaObject : public RefCounted {
|
||||
GDCLASS(JavaObject, RefCounted);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
Ref<JavaClass> base_class;
|
||||
friend class JavaClass;
|
||||
|
||||
jobject instance;
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
JavaObject(const Ref<JavaClass> &p_base, jobject *p_instance);
|
||||
~JavaObject();
|
||||
#endif
|
||||
};
|
||||
|
||||
class JavaClassWrapper : public Object {
|
||||
GDCLASS(JavaClassWrapper, Object);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
RBMap<String, Ref<JavaClass>> class_cache;
|
||||
friend class JavaClass;
|
||||
jmethodID getDeclaredMethods;
|
||||
jmethodID getFields;
|
||||
jmethodID getParameterTypes;
|
||||
jmethodID getReturnType;
|
||||
jmethodID getModifiers;
|
||||
jmethodID getName;
|
||||
jmethodID Class_getName;
|
||||
jmethodID Field_getName;
|
||||
jmethodID Field_getModifiers;
|
||||
jmethodID Field_get;
|
||||
jmethodID Boolean_booleanValue;
|
||||
jmethodID Byte_byteValue;
|
||||
jmethodID Character_characterValue;
|
||||
jmethodID Short_shortValue;
|
||||
jmethodID Integer_integerValue;
|
||||
jmethodID Long_longValue;
|
||||
jmethodID Float_floatValue;
|
||||
jmethodID Double_doubleValue;
|
||||
|
||||
bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig);
|
||||
#endif
|
||||
|
||||
static JavaClassWrapper *singleton;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static JavaClassWrapper *get_singleton() { return singleton; }
|
||||
|
||||
Ref<JavaClass> wrap(const String &p_class);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
JavaClassWrapper(jobject p_activity = nullptr);
|
||||
#else
|
||||
JavaClassWrapper();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // JAVA_CLASS_WRAPPER_H
|
||||
251
engine/platform/android/api/jni_singleton.h
Normal file
251
engine/platform/android/api/jni_singleton.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/**************************************************************************/
|
||||
/* jni_singleton.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef JNI_SINGLETON_H
|
||||
#define JNI_SINGLETON_H
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
#include "jni_utils.h"
|
||||
#endif
|
||||
|
||||
class JNISingleton : public Object {
|
||||
GDCLASS(JNISingleton, Object);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
struct MethodData {
|
||||
jmethodID method;
|
||||
Variant::Type ret_type;
|
||||
Vector<Variant::Type> argtypes;
|
||||
};
|
||||
|
||||
jobject instance;
|
||||
RBMap<StringName, MethodData> method_map;
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
|
||||
#ifdef ANDROID_ENABLED
|
||||
RBMap<StringName, MethodData>::Element *E = method_map.find(p_method);
|
||||
|
||||
// Check the method we're looking for is in the JNISingleton map and that
|
||||
// the arguments match.
|
||||
bool call_error = !E || E->get().argtypes.size() != p_argcount;
|
||||
if (!call_error) {
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
|
||||
call_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (call_error) {
|
||||
// The method is not in this map, defaulting to the regular instance calls.
|
||||
return Object::callp(p_method, p_args, p_argcount, r_error);
|
||||
}
|
||||
|
||||
ERR_FAIL_NULL_V(instance, Variant());
|
||||
|
||||
r_error.error = Callable::CallError::CALL_OK;
|
||||
|
||||
jvalue *v = nullptr;
|
||||
|
||||
if (p_argcount) {
|
||||
v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
|
||||
}
|
||||
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
int res = env->PushLocalFrame(16);
|
||||
|
||||
ERR_FAIL_COND_V(res != 0, Variant());
|
||||
|
||||
List<jobject> to_erase;
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
|
||||
v[i] = vr.val;
|
||||
if (vr.obj) {
|
||||
to_erase.push_back(vr.obj);
|
||||
}
|
||||
}
|
||||
|
||||
Variant ret;
|
||||
|
||||
switch (E->get().ret_type) {
|
||||
case Variant::NIL: {
|
||||
env->CallVoidMethodA(instance, E->get().method, v);
|
||||
} break;
|
||||
case Variant::BOOL: {
|
||||
ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
|
||||
} break;
|
||||
case Variant::INT: {
|
||||
ret = env->CallIntMethodA(instance, E->get().method, v);
|
||||
} break;
|
||||
case Variant::FLOAT: {
|
||||
ret = env->CallFloatMethodA(instance, E->get().method, v);
|
||||
} break;
|
||||
case Variant::STRING: {
|
||||
jobject o = env->CallObjectMethodA(instance, E->get().method, v);
|
||||
ret = jstring_to_string((jstring)o, env);
|
||||
env->DeleteLocalRef(o);
|
||||
} break;
|
||||
case Variant::PACKED_STRING_ARRAY: {
|
||||
jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
|
||||
|
||||
ret = _jobject_to_variant(env, arr);
|
||||
|
||||
env->DeleteLocalRef(arr);
|
||||
} break;
|
||||
case Variant::PACKED_INT32_ARRAY: {
|
||||
jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
|
||||
|
||||
int fCount = env->GetArrayLength(arr);
|
||||
Vector<int> sarr;
|
||||
sarr.resize(fCount);
|
||||
|
||||
int *w = sarr.ptrw();
|
||||
env->GetIntArrayRegion(arr, 0, fCount, w);
|
||||
ret = sarr;
|
||||
env->DeleteLocalRef(arr);
|
||||
} break;
|
||||
case Variant::PACKED_INT64_ARRAY: {
|
||||
jlongArray arr = (jlongArray)env->CallObjectMethodA(instance, E->get().method, v);
|
||||
|
||||
int fCount = env->GetArrayLength(arr);
|
||||
Vector<int64_t> sarr;
|
||||
sarr.resize(fCount);
|
||||
|
||||
int64_t *w = sarr.ptrw();
|
||||
env->GetLongArrayRegion(arr, 0, fCount, w);
|
||||
ret = sarr;
|
||||
env->DeleteLocalRef(arr);
|
||||
} break;
|
||||
case Variant::PACKED_FLOAT32_ARRAY: {
|
||||
jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
|
||||
|
||||
int fCount = env->GetArrayLength(arr);
|
||||
Vector<float> sarr;
|
||||
sarr.resize(fCount);
|
||||
|
||||
float *w = sarr.ptrw();
|
||||
env->GetFloatArrayRegion(arr, 0, fCount, w);
|
||||
ret = sarr;
|
||||
env->DeleteLocalRef(arr);
|
||||
} break;
|
||||
case Variant::PACKED_FLOAT64_ARRAY: {
|
||||
jdoubleArray arr = (jdoubleArray)env->CallObjectMethodA(instance, E->get().method, v);
|
||||
|
||||
int fCount = env->GetArrayLength(arr);
|
||||
Vector<double> sarr;
|
||||
sarr.resize(fCount);
|
||||
|
||||
double *w = sarr.ptrw();
|
||||
env->GetDoubleArrayRegion(arr, 0, fCount, w);
|
||||
ret = sarr;
|
||||
env->DeleteLocalRef(arr);
|
||||
} break;
|
||||
case Variant::DICTIONARY: {
|
||||
jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
|
||||
ret = _jobject_to_variant(env, obj);
|
||||
env->DeleteLocalRef(obj);
|
||||
|
||||
} break;
|
||||
default: {
|
||||
env->PopLocalFrame(nullptr);
|
||||
ERR_FAIL_V(Variant());
|
||||
} break;
|
||||
}
|
||||
|
||||
while (to_erase.size()) {
|
||||
env->DeleteLocalRef(to_erase.front()->get());
|
||||
to_erase.pop_front();
|
||||
}
|
||||
|
||||
env->PopLocalFrame(nullptr);
|
||||
|
||||
return ret;
|
||||
#else // ANDROID_ENABLED
|
||||
|
||||
// Defaulting to the regular instance calls.
|
||||
return Object::callp(p_method, p_args, p_argcount, r_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
jobject get_instance() const {
|
||||
return instance;
|
||||
}
|
||||
|
||||
void set_instance(jobject p_instance) {
|
||||
instance = p_instance;
|
||||
}
|
||||
|
||||
void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
|
||||
MethodData md;
|
||||
md.method = p_method;
|
||||
md.argtypes = p_args;
|
||||
md.ret_type = p_ret_type;
|
||||
method_map[p_name] = md;
|
||||
}
|
||||
|
||||
void add_signal(const StringName &p_name, const Vector<Variant::Type> &p_args) {
|
||||
MethodInfo mi;
|
||||
mi.name = p_name;
|
||||
for (int i = 0; i < p_args.size(); i++) {
|
||||
mi.arguments.push_back(PropertyInfo(p_args[i], "arg" + itos(i + 1)));
|
||||
}
|
||||
ADD_SIGNAL(mi);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
JNISingleton() {
|
||||
#ifdef ANDROID_ENABLED
|
||||
instance = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
~JNISingleton() {
|
||||
#ifdef ANDROID_ENABLED
|
||||
method_map.clear();
|
||||
if (instance) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
|
||||
env->DeleteGlobalRef(instance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif // JNI_SINGLETON_H
|
||||
363
engine/platform/android/audio_driver_opensl.cpp
Normal file
363
engine/platform/android/audio_driver_opensl.cpp
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/**************************************************************************/
|
||||
/* audio_driver_opensl.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "audio_driver_opensl.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_NUMBER_INTERFACES 3
|
||||
#define MAX_NUMBER_OUTPUT_DEVICES 6
|
||||
|
||||
/* Structure for passing information to callback function */
|
||||
|
||||
void AudioDriverOpenSL::_buffer_callback(
|
||||
SLAndroidSimpleBufferQueueItf queueItf) {
|
||||
bool mix = true;
|
||||
|
||||
if (pause) {
|
||||
mix = false;
|
||||
} else {
|
||||
mix = mutex.try_lock();
|
||||
}
|
||||
|
||||
if (mix) {
|
||||
audio_server_process(buffer_size, mixdown_buffer);
|
||||
} else {
|
||||
int32_t *src_buff = mixdown_buffer;
|
||||
for (unsigned int i = 0; i < buffer_size * 2; i++) {
|
||||
src_buff[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mix) {
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
const int32_t *src_buff = mixdown_buffer;
|
||||
|
||||
int16_t *ptr = (int16_t *)buffers[last_free];
|
||||
last_free = (last_free + 1) % BUFFER_COUNT;
|
||||
|
||||
for (unsigned int i = 0; i < buffer_size * 2; i++) {
|
||||
ptr[i] = src_buff[i] >> 16;
|
||||
}
|
||||
|
||||
(*queueItf)->Enqueue(queueItf, ptr, 4 * buffer_size);
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::_buffer_callbacks(
|
||||
SLAndroidSimpleBufferQueueItf queueItf,
|
||||
void *pContext) {
|
||||
AudioDriverOpenSL *ad = static_cast<AudioDriverOpenSL *>(pContext);
|
||||
|
||||
ad->_buffer_callback(queueItf);
|
||||
}
|
||||
|
||||
Error AudioDriverOpenSL::init() {
|
||||
SLresult res;
|
||||
SLEngineOption EngineOption[] = {
|
||||
{ (SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE }
|
||||
};
|
||||
res = slCreateEngine(&sl, 1, EngineOption, 0, nullptr, nullptr);
|
||||
ERR_FAIL_COND_V_MSG(res != SL_RESULT_SUCCESS, ERR_INVALID_PARAMETER, "Could not initialize OpenSL.");
|
||||
|
||||
res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
|
||||
ERR_FAIL_COND_V_MSG(res != SL_RESULT_SUCCESS, ERR_INVALID_PARAMETER, "Could not realize OpenSL.");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::start() {
|
||||
active = false;
|
||||
|
||||
SLresult res;
|
||||
|
||||
buffer_size = 1024;
|
||||
|
||||
for (int i = 0; i < BUFFER_COUNT; i++) {
|
||||
buffers[i] = memnew_arr(int16_t, buffer_size * 2);
|
||||
memset(buffers[i], 0, buffer_size * 4);
|
||||
}
|
||||
|
||||
mixdown_buffer = memnew_arr(int32_t, buffer_size * 2);
|
||||
|
||||
/* Callback context for the buffer queue callback function */
|
||||
|
||||
/* Get the SL Engine Interface which is implicit */
|
||||
res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void *)&EngineItf);
|
||||
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
|
||||
{
|
||||
const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB };
|
||||
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
|
||||
res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0, ids, req);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
// Realizing the Output Mix object in synchronous mode.
|
||||
res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, BUFFER_COUNT };
|
||||
/* Setup the format of the content in the buffer queue */
|
||||
pcm.formatType = SL_DATAFORMAT_PCM;
|
||||
pcm.numChannels = 2;
|
||||
pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
|
||||
pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||||
pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||||
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
pcm.endianness = SL_BYTEORDER_BIGENDIAN;
|
||||
#else
|
||||
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
#endif
|
||||
audioSource.pFormat = (void *)&pcm;
|
||||
audioSource.pLocator = (void *)&loc_bufq;
|
||||
|
||||
/* Setup the data sink structure */
|
||||
locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||
locator_outputmix.outputMix = OutputMix;
|
||||
audioSink.pLocator = (void *)&locator_outputmix;
|
||||
audioSink.pFormat = nullptr;
|
||||
|
||||
/* Create the music player */
|
||||
{
|
||||
const SLInterfaceID ids[2] = { SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND };
|
||||
const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
|
||||
|
||||
res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 1, ids, req);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
}
|
||||
/* Realizing the player in synchronous mode. */
|
||||
res = (*player)->Realize(player, SL_BOOLEAN_FALSE);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
/* Get seek and play interfaces */
|
||||
res = (*player)->GetInterface(player, SL_IID_PLAY, (void *)&playItf);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
|
||||
(void *)&bufferQueueItf);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
/* Setup to receive buffer queue event callbacks */
|
||||
res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf, _buffer_callbacks, this);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
|
||||
last_free = 0;
|
||||
|
||||
//fill up buffers
|
||||
for (int i = 0; i < BUFFER_COUNT; i++) {
|
||||
/* Enqueue a few buffers to get the ball rolling */
|
||||
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, buffers[i], 4 * buffer_size); /* Size given in */
|
||||
}
|
||||
|
||||
res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
|
||||
active = true;
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::_record_buffer_callback(SLAndroidSimpleBufferQueueItf queueItf) {
|
||||
for (int i = 0; i < rec_buffer.size(); i++) {
|
||||
int32_t sample = rec_buffer[i] << 16;
|
||||
input_buffer_write(sample);
|
||||
input_buffer_write(sample); // call twice to convert to Stereo
|
||||
}
|
||||
|
||||
SLresult res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t));
|
||||
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::_record_buffer_callbacks(SLAndroidSimpleBufferQueueItf queueItf, void *pContext) {
|
||||
AudioDriverOpenSL *ad = static_cast<AudioDriverOpenSL *>(pContext);
|
||||
|
||||
ad->_record_buffer_callback(queueItf);
|
||||
}
|
||||
|
||||
Error AudioDriverOpenSL::init_input_device() {
|
||||
SLDataLocator_IODevice loc_dev = {
|
||||
SL_DATALOCATOR_IODEVICE,
|
||||
SL_IODEVICE_AUDIOINPUT,
|
||||
SL_DEFAULTDEVICEID_AUDIOINPUT,
|
||||
nullptr
|
||||
};
|
||||
SLDataSource recSource = { &loc_dev, nullptr };
|
||||
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
|
||||
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
|
||||
2
|
||||
};
|
||||
SLDataFormat_PCM format_pcm = {
|
||||
SL_DATAFORMAT_PCM,
|
||||
1,
|
||||
SL_SAMPLINGRATE_44_1,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_SPEAKER_FRONT_CENTER,
|
||||
SL_BYTEORDER_LITTLEENDIAN
|
||||
};
|
||||
SLDataSink recSnk = { &loc_bq, &format_pcm };
|
||||
|
||||
const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
|
||||
const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
|
||||
|
||||
SLresult res = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recSnk, 2, ids, req);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void *)&recordItf);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void *)&recordBufferQueueItf);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recordBufferQueueItf)->RegisterCallback(recordBufferQueueItf, _record_buffer_callbacks, this);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
SLuint32 state;
|
||||
res = (*recordItf)->GetRecordState(recordItf, &state);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
if (state != SL_RECORDSTATE_STOPPED) {
|
||||
res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
}
|
||||
|
||||
const int rec_buffer_frames = 2048;
|
||||
rec_buffer.resize(rec_buffer_frames);
|
||||
input_buffer_init(rec_buffer_frames);
|
||||
|
||||
res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t));
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error AudioDriverOpenSL::input_start() {
|
||||
if (recordItf || recordBufferQueueItf) {
|
||||
return ERR_ALREADY_IN_USE;
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->request_permission("RECORD_AUDIO")) {
|
||||
return init_input_device();
|
||||
}
|
||||
|
||||
WARN_PRINT("Unable to start audio capture - No RECORD_AUDIO permission");
|
||||
return ERR_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
Error AudioDriverOpenSL::input_stop() {
|
||||
if (!recordItf || !recordBufferQueueItf) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
SLuint32 state;
|
||||
SLresult res = (*recordItf)->GetRecordState(recordItf, &state);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
if (state != SL_RECORDSTATE_STOPPED) {
|
||||
res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
|
||||
res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
|
||||
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int AudioDriverOpenSL::get_mix_rate() const {
|
||||
return 44100; // hardcoded for Android, as selected by SL_SAMPLINGRATE_44_1
|
||||
}
|
||||
|
||||
AudioDriver::SpeakerMode AudioDriverOpenSL::get_speaker_mode() const {
|
||||
return SPEAKER_MODE_STEREO;
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::lock() {
|
||||
if (active) {
|
||||
mutex.lock();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::unlock() {
|
||||
if (active) {
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::finish() {
|
||||
if (recordItf) {
|
||||
(*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
|
||||
recordItf = nullptr;
|
||||
}
|
||||
if (recorder) {
|
||||
(*recorder)->Destroy(recorder);
|
||||
recorder = nullptr;
|
||||
}
|
||||
if (playItf) {
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
|
||||
playItf = nullptr;
|
||||
}
|
||||
if (player) {
|
||||
(*player)->Destroy(player);
|
||||
player = nullptr;
|
||||
}
|
||||
if (OutputMix) {
|
||||
(*OutputMix)->Destroy(OutputMix);
|
||||
OutputMix = nullptr;
|
||||
}
|
||||
if (sl) {
|
||||
(*sl)->Destroy(sl);
|
||||
sl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDriverOpenSL::set_pause(bool p_pause) {
|
||||
pause = p_pause;
|
||||
|
||||
if (active && playItf) {
|
||||
if (pause) {
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED);
|
||||
} else {
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioDriverOpenSL::AudioDriverOpenSL() {
|
||||
}
|
||||
111
engine/platform/android/audio_driver_opensl.h
Normal file
111
engine/platform/android/audio_driver_opensl.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/**************************************************************************/
|
||||
/* audio_driver_opensl.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef AUDIO_DRIVER_OPENSL_H
|
||||
#define AUDIO_DRIVER_OPENSL_H
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
#include "servers/audio_server.h"
|
||||
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
|
||||
class AudioDriverOpenSL : public AudioDriver {
|
||||
bool active = false;
|
||||
Mutex mutex;
|
||||
|
||||
enum {
|
||||
BUFFER_COUNT = 2
|
||||
};
|
||||
|
||||
bool pause = false;
|
||||
|
||||
uint32_t buffer_size = 0;
|
||||
int16_t *buffers[BUFFER_COUNT] = {};
|
||||
int32_t *mixdown_buffer = nullptr;
|
||||
int last_free = 0;
|
||||
|
||||
Vector<int16_t> rec_buffer;
|
||||
|
||||
SLPlayItf playItf = nullptr;
|
||||
SLRecordItf recordItf = nullptr;
|
||||
SLObjectItf sl = nullptr;
|
||||
SLEngineItf EngineItf = nullptr;
|
||||
SLObjectItf OutputMix = nullptr;
|
||||
SLObjectItf player = nullptr;
|
||||
SLObjectItf recorder = nullptr;
|
||||
SLAndroidSimpleBufferQueueItf bufferQueueItf = nullptr;
|
||||
SLAndroidSimpleBufferQueueItf recordBufferQueueItf = nullptr;
|
||||
SLDataSource audioSource;
|
||||
SLDataFormat_PCM pcm;
|
||||
SLDataSink audioSink;
|
||||
SLDataLocator_OutputMix locator_outputmix;
|
||||
|
||||
static AudioDriverOpenSL *s_ad;
|
||||
|
||||
void _buffer_callback(
|
||||
SLAndroidSimpleBufferQueueItf queueItf);
|
||||
|
||||
static void _buffer_callbacks(
|
||||
SLAndroidSimpleBufferQueueItf queueItf,
|
||||
void *pContext);
|
||||
|
||||
void _record_buffer_callback(
|
||||
SLAndroidSimpleBufferQueueItf queueItf);
|
||||
|
||||
static void _record_buffer_callbacks(
|
||||
SLAndroidSimpleBufferQueueItf queueItf,
|
||||
void *pContext);
|
||||
|
||||
Error init_input_device();
|
||||
|
||||
public:
|
||||
virtual const char *get_name() const override {
|
||||
return "Android";
|
||||
}
|
||||
|
||||
virtual Error init() override;
|
||||
virtual void start() override;
|
||||
virtual int get_mix_rate() const override;
|
||||
virtual SpeakerMode get_speaker_mode() const override;
|
||||
|
||||
virtual void lock() override;
|
||||
virtual void unlock() override;
|
||||
virtual void finish() override;
|
||||
|
||||
virtual Error input_start() override;
|
||||
virtual Error input_stop() override;
|
||||
|
||||
void set_pause(bool p_pause);
|
||||
|
||||
AudioDriverOpenSL();
|
||||
};
|
||||
|
||||
#endif // AUDIO_DRIVER_OPENSL_H
|
||||
211
engine/platform/android/detect.py
Normal file
211
engine/platform/android/detect.py
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from methods import print_error, print_warning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from SCons.Script.SConscript import SConsEnvironment
|
||||
|
||||
|
||||
def get_name():
|
||||
return "Android"
|
||||
|
||||
|
||||
def can_build():
|
||||
return os.path.exists(get_env_android_sdk_root())
|
||||
|
||||
|
||||
def get_opts():
|
||||
from SCons.Variables import BoolVariable
|
||||
|
||||
return [
|
||||
("ANDROID_HOME", "Path to the Android SDK", get_env_android_sdk_root()),
|
||||
(
|
||||
"ndk_platform",
|
||||
'Target platform (android-<api>, e.g. "android-' + str(get_min_target_api()) + '")',
|
||||
"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),
|
||||
]
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"EditorExportPlatformAndroid",
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
||||
|
||||
|
||||
# Return the ANDROID_HOME environment variable.
|
||||
def get_env_android_sdk_root():
|
||||
return os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT", ""))
|
||||
|
||||
|
||||
def get_min_sdk_version(platform):
|
||||
return int(platform.split("-")[1])
|
||||
|
||||
|
||||
def get_android_ndk_root(env: "SConsEnvironment"):
|
||||
return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
|
||||
|
||||
|
||||
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
|
||||
def get_ndk_version():
|
||||
return "23.2.8568313"
|
||||
|
||||
|
||||
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
|
||||
def get_min_target_api():
|
||||
return 21
|
||||
|
||||
|
||||
def get_flags():
|
||||
return {
|
||||
"arch": "arm64",
|
||||
"target": "template_debug",
|
||||
"supported": ["mono"],
|
||||
}
|
||||
|
||||
|
||||
# Check if Android NDK version is installed
|
||||
# If not, install it.
|
||||
def install_ndk_if_needed(env: "SConsEnvironment"):
|
||||
sdk_root = env["ANDROID_HOME"]
|
||||
if not os.path.exists(get_android_ndk_root(env)):
|
||||
extension = ".bat" if os.name == "nt" else ""
|
||||
sdkmanager = sdk_root + "/cmdline-tools/latest/bin/sdkmanager" + extension
|
||||
if os.path.exists(sdkmanager):
|
||||
# Install the Android NDK
|
||||
print("Installing Android NDK...")
|
||||
ndk_download_args = "ndk;" + get_ndk_version()
|
||||
subprocess.check_call([sdkmanager, ndk_download_args])
|
||||
else:
|
||||
print_error(
|
||||
f'Cannot find "{sdkmanager}". Please ensure ANDROID_HOME is correct and cmdline-tools'
|
||||
f' are installed, or install NDK version "{get_ndk_version()}" manually.'
|
||||
)
|
||||
sys.exit(255)
|
||||
env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env)
|
||||
|
||||
|
||||
def configure(env: "SConsEnvironment"):
|
||||
# Validate arch.
|
||||
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
|
||||
if env["arch"] not in supported_arches:
|
||||
print_error(
|
||||
'Unsupported CPU architecture "%s" for Android. Supported architectures are: %s.'
|
||||
% (env["arch"], ", ".join(supported_arches))
|
||||
)
|
||||
sys.exit(255)
|
||||
|
||||
if get_min_sdk_version(env["ndk_platform"]) < get_min_target_api():
|
||||
print_warning(
|
||||
"Minimum supported Android target api is %d. Forcing target api %d."
|
||||
% (get_min_target_api(), get_min_target_api())
|
||||
)
|
||||
env["ndk_platform"] = "android-" + str(get_min_target_api())
|
||||
|
||||
install_ndk_if_needed(env)
|
||||
ndk_root = env["ANDROID_NDK_ROOT"]
|
||||
|
||||
# Architecture
|
||||
|
||||
if env["arch"] == "arm32":
|
||||
target_triple = "armv7a-linux-androideabi"
|
||||
elif env["arch"] == "arm64":
|
||||
target_triple = "aarch64-linux-android"
|
||||
elif env["arch"] == "x86_32":
|
||||
target_triple = "i686-linux-android"
|
||||
elif env["arch"] == "x86_64":
|
||||
target_triple = "x86_64-linux-android"
|
||||
|
||||
target_option = ["-target", target_triple + str(get_min_sdk_version(env["ndk_platform"]))]
|
||||
env.Append(ASFLAGS=[target_option, "-c"])
|
||||
env.Append(CCFLAGS=target_option)
|
||||
env.Append(LINKFLAGS=target_option)
|
||||
|
||||
# LTO
|
||||
|
||||
if env["lto"] == "auto": # LTO benefits for Android (size, performance) haven't been clearly established yet.
|
||||
env["lto"] = "none"
|
||||
|
||||
if env["lto"] != "none":
|
||||
if env["lto"] == "thin":
|
||||
env.Append(CCFLAGS=["-flto=thin"])
|
||||
env.Append(LINKFLAGS=["-flto=thin"])
|
||||
else:
|
||||
env.Append(CCFLAGS=["-flto"])
|
||||
env.Append(LINKFLAGS=["-flto"])
|
||||
|
||||
# Compiler configuration
|
||||
|
||||
env["SHLIBSUFFIX"] = ".so"
|
||||
|
||||
if env["PLATFORM"] == "win32":
|
||||
env.use_windows_spawn_fix()
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
host_subpath = "linux-x86_64"
|
||||
elif sys.platform.startswith("darwin"):
|
||||
host_subpath = "darwin-x86_64"
|
||||
elif sys.platform.startswith("win"):
|
||||
if platform.machine().endswith("64"):
|
||||
host_subpath = "windows-x86_64"
|
||||
else:
|
||||
host_subpath = "windows"
|
||||
|
||||
toolchain_path = ndk_root + "/toolchains/llvm/prebuilt/" + host_subpath
|
||||
compiler_path = toolchain_path + "/bin"
|
||||
|
||||
env["CC"] = compiler_path + "/clang"
|
||||
env["CXX"] = compiler_path + "/clang++"
|
||||
env["AR"] = compiler_path + "/llvm-ar"
|
||||
env["RANLIB"] = compiler_path + "/llvm-ranlib"
|
||||
env["AS"] = compiler_path + "/clang"
|
||||
|
||||
env.Append(
|
||||
CCFLAGS=(
|
||||
"-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split()
|
||||
)
|
||||
)
|
||||
|
||||
if get_min_sdk_version(env["ndk_platform"]) >= 24:
|
||||
env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
|
||||
|
||||
if env["arch"] == "x86_32":
|
||||
# The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least
|
||||
env.Append(CCFLAGS=["-mstackrealign"])
|
||||
elif env["arch"] == "arm32":
|
||||
env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
|
||||
env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
|
||||
env.Append(CPPDEFINES=["__ARM_NEON__"])
|
||||
elif env["arch"] == "arm64":
|
||||
env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
|
||||
env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
|
||||
|
||||
env.Append(CCFLAGS=["-ffp-contract=off"])
|
||||
|
||||
# Link flags
|
||||
|
||||
env.Append(LINKFLAGS="-Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now".split())
|
||||
env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so")
|
||||
|
||||
env.Prepend(CPPPATH=["#platform/android"])
|
||||
env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
|
||||
env.Append(LIBS=["OpenSLES", "EGL", "android", "log", "z", "dl"])
|
||||
|
||||
if env["vulkan"]:
|
||||
env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
|
||||
if not env["use_volk"]:
|
||||
env.Append(LIBS=["vulkan"])
|
||||
|
||||
if env["opengl3"]:
|
||||
env.Append(CPPDEFINES=["GLES3_ENABLED"])
|
||||
env.Append(LIBS=["GLESv3"])
|
||||
360
engine/platform/android/dir_access_jandroid.cpp
Normal file
360
engine/platform/android/dir_access_jandroid.cpp
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/**************************************************************************/
|
||||
/* dir_access_jandroid.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "dir_access_jandroid.h"
|
||||
|
||||
#include "string_android.h"
|
||||
#include "thread_jandroid.h"
|
||||
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
jobject DirAccessJAndroid::dir_access_handler = nullptr;
|
||||
jclass DirAccessJAndroid::cls = nullptr;
|
||||
jmethodID DirAccessJAndroid::_dir_open = nullptr;
|
||||
jmethodID DirAccessJAndroid::_dir_next = nullptr;
|
||||
jmethodID DirAccessJAndroid::_dir_close = nullptr;
|
||||
jmethodID DirAccessJAndroid::_dir_is_dir = nullptr;
|
||||
jmethodID DirAccessJAndroid::_dir_exists = nullptr;
|
||||
jmethodID DirAccessJAndroid::_file_exists = nullptr;
|
||||
jmethodID DirAccessJAndroid::_get_drive_count = nullptr;
|
||||
jmethodID DirAccessJAndroid::_get_drive = nullptr;
|
||||
jmethodID DirAccessJAndroid::_make_dir = nullptr;
|
||||
jmethodID DirAccessJAndroid::_get_space_left = nullptr;
|
||||
jmethodID DirAccessJAndroid::_rename = nullptr;
|
||||
jmethodID DirAccessJAndroid::_remove = nullptr;
|
||||
jmethodID DirAccessJAndroid::_current_is_hidden = nullptr;
|
||||
|
||||
Error DirAccessJAndroid::list_dir_begin() {
|
||||
list_dir_end();
|
||||
int res = dir_open(current_dir);
|
||||
if (res <= 0) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
id = res;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String DirAccessJAndroid::get_next() {
|
||||
ERR_FAIL_COND_V(id == 0, "");
|
||||
if (_dir_next) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, "");
|
||||
jstring str = (jstring)env->CallObjectMethod(dir_access_handler, _dir_next, get_access_type(), id);
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String ret = jstring_to_string((jstring)str, env);
|
||||
env->DeleteLocalRef((jobject)str);
|
||||
return ret;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool DirAccessJAndroid::current_is_dir() const {
|
||||
if (_dir_is_dir) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
return env->CallBooleanMethod(dir_access_handler, _dir_is_dir, get_access_type(), id);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirAccessJAndroid::current_is_hidden() const {
|
||||
if (_current_is_hidden) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
return env->CallBooleanMethod(dir_access_handler, _current_is_hidden, get_access_type(), id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DirAccessJAndroid::list_dir_end() {
|
||||
if (id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dir_close(id);
|
||||
id = 0;
|
||||
}
|
||||
|
||||
int DirAccessJAndroid::get_drive_count() {
|
||||
if (_get_drive_count) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, 0);
|
||||
return env->CallIntMethod(dir_access_handler, _get_drive_count, get_access_type());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
String DirAccessJAndroid::get_drive(int p_drive) {
|
||||
if (_get_drive) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, "");
|
||||
jstring j_drive = (jstring)env->CallObjectMethod(dir_access_handler, _get_drive, get_access_type(), p_drive);
|
||||
if (!j_drive) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String drive = jstring_to_string(j_drive, env);
|
||||
env->DeleteLocalRef(j_drive);
|
||||
return drive;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
String DirAccessJAndroid::_get_root_string() const {
|
||||
if (get_access_type() == ACCESS_FILESYSTEM) {
|
||||
return "/";
|
||||
}
|
||||
return DirAccessUnix::_get_root_string();
|
||||
}
|
||||
|
||||
String DirAccessJAndroid::get_current_dir(bool p_include_drive) const {
|
||||
String base = _get_root_path();
|
||||
String bd = current_dir;
|
||||
if (!base.is_empty()) {
|
||||
bd = current_dir.replace_first(base, "");
|
||||
}
|
||||
|
||||
String root_string = _get_root_string();
|
||||
if (bd.begins_with(root_string)) {
|
||||
return bd;
|
||||
} else if (bd.begins_with("/")) {
|
||||
return root_string + bd.substr(1, bd.length());
|
||||
} else {
|
||||
return root_string + bd;
|
||||
}
|
||||
}
|
||||
|
||||
Error DirAccessJAndroid::change_dir(String p_dir) {
|
||||
String new_dir = get_absolute_path(p_dir);
|
||||
if (new_dir == current_dir) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (!dir_exists(new_dir)) {
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
current_dir = new_dir;
|
||||
return OK;
|
||||
}
|
||||
|
||||
String DirAccessJAndroid::get_absolute_path(String p_path) {
|
||||
if (current_dir != "" && p_path == current_dir) {
|
||||
return current_dir;
|
||||
}
|
||||
|
||||
if (p_path.is_relative_path()) {
|
||||
p_path = get_current_dir().path_join(p_path);
|
||||
}
|
||||
|
||||
p_path = fix_path(p_path);
|
||||
p_path = p_path.simplify_path();
|
||||
return p_path;
|
||||
}
|
||||
|
||||
bool DirAccessJAndroid::file_exists(String p_file) {
|
||||
if (_file_exists) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
|
||||
String path = get_absolute_path(p_file);
|
||||
jstring j_path = env->NewStringUTF(path.utf8().get_data());
|
||||
bool result = env->CallBooleanMethod(dir_access_handler, _file_exists, get_access_type(), j_path);
|
||||
env->DeleteLocalRef(j_path);
|
||||
return result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirAccessJAndroid::dir_exists(String p_dir) {
|
||||
if (_dir_exists) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
|
||||
String path = get_absolute_path(p_dir);
|
||||
jstring j_path = env->NewStringUTF(path.utf8().get_data());
|
||||
bool result = env->CallBooleanMethod(dir_access_handler, _dir_exists, get_access_type(), j_path);
|
||||
env->DeleteLocalRef(j_path);
|
||||
return result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Error DirAccessJAndroid::make_dir_recursive(const String &p_dir) {
|
||||
// Check if the directory exists already
|
||||
if (dir_exists(p_dir)) {
|
||||
return ERR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
if (_make_dir) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
|
||||
|
||||
String path = get_absolute_path(p_dir);
|
||||
jstring j_dir = env->NewStringUTF(path.utf8().get_data());
|
||||
bool result = env->CallBooleanMethod(dir_access_handler, _make_dir, get_access_type(), j_dir);
|
||||
env->DeleteLocalRef(j_dir);
|
||||
if (result) {
|
||||
return OK;
|
||||
} else {
|
||||
return FAILED;
|
||||
}
|
||||
} else {
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
Error DirAccessJAndroid::make_dir(String p_dir) {
|
||||
return make_dir_recursive(p_dir);
|
||||
}
|
||||
|
||||
Error DirAccessJAndroid::rename(String p_from, String p_to) {
|
||||
if (_rename) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
|
||||
|
||||
String from_path = get_absolute_path(p_from);
|
||||
jstring j_from = env->NewStringUTF(from_path.utf8().get_data());
|
||||
|
||||
String to_path = get_absolute_path(p_to);
|
||||
jstring j_to = env->NewStringUTF(to_path.utf8().get_data());
|
||||
|
||||
bool result = env->CallBooleanMethod(dir_access_handler, _rename, get_access_type(), j_from, j_to);
|
||||
env->DeleteLocalRef(j_from);
|
||||
env->DeleteLocalRef(j_to);
|
||||
if (result) {
|
||||
return OK;
|
||||
} else {
|
||||
return FAILED;
|
||||
}
|
||||
} else {
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
Error DirAccessJAndroid::remove(String p_name) {
|
||||
if (_remove) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
|
||||
|
||||
String path = get_absolute_path(p_name);
|
||||
jstring j_name = env->NewStringUTF(path.utf8().get_data());
|
||||
bool result = env->CallBooleanMethod(dir_access_handler, _remove, get_access_type(), j_name);
|
||||
env->DeleteLocalRef(j_name);
|
||||
if (result) {
|
||||
return OK;
|
||||
} else {
|
||||
return FAILED;
|
||||
}
|
||||
} else {
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t DirAccessJAndroid::get_space_left() {
|
||||
if (_get_space_left) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, 0);
|
||||
return env->CallLongMethod(dir_access_handler, _get_space_left, get_access_type());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DirAccessJAndroid::setup(jobject p_dir_access_handler) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
dir_access_handler = env->NewGlobalRef(p_dir_access_handler);
|
||||
|
||||
jclass c = env->GetObjectClass(dir_access_handler);
|
||||
cls = (jclass)env->NewGlobalRef(c);
|
||||
|
||||
_dir_open = env->GetMethodID(cls, "dirOpen", "(ILjava/lang/String;)I");
|
||||
_dir_next = env->GetMethodID(cls, "dirNext", "(II)Ljava/lang/String;");
|
||||
_dir_close = env->GetMethodID(cls, "dirClose", "(II)V");
|
||||
_dir_is_dir = env->GetMethodID(cls, "dirIsDir", "(II)Z");
|
||||
_dir_exists = env->GetMethodID(cls, "dirExists", "(ILjava/lang/String;)Z");
|
||||
_file_exists = env->GetMethodID(cls, "fileExists", "(ILjava/lang/String;)Z");
|
||||
_get_drive_count = env->GetMethodID(cls, "getDriveCount", "(I)I");
|
||||
_get_drive = env->GetMethodID(cls, "getDrive", "(II)Ljava/lang/String;");
|
||||
_make_dir = env->GetMethodID(cls, "makeDir", "(ILjava/lang/String;)Z");
|
||||
_get_space_left = env->GetMethodID(cls, "getSpaceLeft", "(I)J");
|
||||
_rename = env->GetMethodID(cls, "rename", "(ILjava/lang/String;Ljava/lang/String;)Z");
|
||||
_remove = env->GetMethodID(cls, "remove", "(ILjava/lang/String;)Z");
|
||||
_current_is_hidden = env->GetMethodID(cls, "isCurrentHidden", "(II)Z");
|
||||
}
|
||||
|
||||
void DirAccessJAndroid::terminate() {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
|
||||
env->DeleteGlobalRef(cls);
|
||||
env->DeleteGlobalRef(dir_access_handler);
|
||||
}
|
||||
|
||||
DirAccessJAndroid::DirAccessJAndroid() {
|
||||
}
|
||||
|
||||
DirAccessJAndroid::~DirAccessJAndroid() {
|
||||
list_dir_end();
|
||||
}
|
||||
|
||||
int DirAccessJAndroid::dir_open(String p_path) {
|
||||
if (_dir_open) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, 0);
|
||||
|
||||
String path = get_absolute_path(p_path);
|
||||
jstring js = env->NewStringUTF(path.utf8().get_data());
|
||||
int dirId = env->CallIntMethod(dir_access_handler, _dir_open, get_access_type(), js);
|
||||
env->DeleteLocalRef(js);
|
||||
return dirId;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DirAccessJAndroid::dir_close(int p_id) {
|
||||
if (_dir_close) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
env->CallVoidMethod(dir_access_handler, _dir_close, get_access_type(), p_id);
|
||||
}
|
||||
}
|
||||
108
engine/platform/android/dir_access_jandroid.h
Normal file
108
engine/platform/android/dir_access_jandroid.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**************************************************************************/
|
||||
/* dir_access_jandroid.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DIR_ACCESS_JANDROID_H
|
||||
#define DIR_ACCESS_JANDROID_H
|
||||
|
||||
#include "java_godot_lib_jni.h"
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "drivers/unix/dir_access_unix.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/// Android implementation of the DirAccess interface used to provide access to
|
||||
/// ACCESS_FILESYSTEM and ACCESS_RESOURCES directory resources.
|
||||
/// The implementation use jni in order to comply with Android filesystem
|
||||
/// access restriction.
|
||||
class DirAccessJAndroid : public DirAccessUnix {
|
||||
static jobject dir_access_handler;
|
||||
static jclass cls;
|
||||
|
||||
static jmethodID _dir_open;
|
||||
static jmethodID _dir_next;
|
||||
static jmethodID _dir_close;
|
||||
static jmethodID _dir_is_dir;
|
||||
static jmethodID _dir_exists;
|
||||
static jmethodID _file_exists;
|
||||
static jmethodID _get_drive_count;
|
||||
static jmethodID _get_drive;
|
||||
static jmethodID _make_dir;
|
||||
static jmethodID _get_space_left;
|
||||
static jmethodID _rename;
|
||||
static jmethodID _remove;
|
||||
static jmethodID _current_is_hidden;
|
||||
|
||||
public:
|
||||
virtual Error list_dir_begin() override; ///< This starts dir listing
|
||||
virtual String get_next() override;
|
||||
virtual bool current_is_dir() const override;
|
||||
virtual bool current_is_hidden() const override;
|
||||
virtual void list_dir_end() override; ///<
|
||||
|
||||
virtual int get_drive_count() override;
|
||||
virtual String get_drive(int p_drive) override;
|
||||
virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
|
||||
|
||||
virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
|
||||
|
||||
virtual bool file_exists(String p_file) override;
|
||||
virtual bool dir_exists(String p_dir) override;
|
||||
|
||||
virtual Error make_dir(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;
|
||||
|
||||
virtual bool is_link(String p_file) override { return false; }
|
||||
virtual String read_link(String p_file) override { return p_file; }
|
||||
virtual Error create_link(String p_source, String p_target) override { return FAILED; }
|
||||
|
||||
virtual uint64_t get_space_left() override;
|
||||
|
||||
static void setup(jobject p_dir_access_handler);
|
||||
static void terminate();
|
||||
|
||||
DirAccessJAndroid();
|
||||
~DirAccessJAndroid();
|
||||
|
||||
protected:
|
||||
String _get_root_string() const override;
|
||||
|
||||
private:
|
||||
int id = 0;
|
||||
|
||||
int dir_open(String p_path);
|
||||
void dir_close(int p_id);
|
||||
String get_absolute_path(String p_path);
|
||||
};
|
||||
|
||||
#endif // DIR_ACCESS_JANDROID_H
|
||||
794
engine/platform/android/display_server_android.cpp
Normal file
794
engine/platform/android/display_server_android.cpp
Normal file
|
|
@ -0,0 +1,794 @@
|
|||
/**************************************************************************/
|
||||
/* display_server_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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "display_server_android.h"
|
||||
|
||||
#include "java_godot_io_wrapper.h"
|
||||
#include "java_godot_wrapper.h"
|
||||
#include "os_android.h"
|
||||
#include "tts_android.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "rendering_context_driver_vulkan_android.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
#include "drivers/gles3/rasterizer_gles3.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
|
||||
DisplayServerAndroid *DisplayServerAndroid::get_singleton() {
|
||||
return static_cast<DisplayServerAndroid *>(DisplayServer::get_singleton());
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::has_feature(Feature p_feature) const {
|
||||
switch (p_feature) {
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
case FEATURE_GLOBAL_MENU: {
|
||||
return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
|
||||
} break;
|
||||
#endif
|
||||
case FEATURE_CURSOR_SHAPE:
|
||||
//case FEATURE_CUSTOM_CURSOR_SHAPE:
|
||||
//case FEATURE_HIDPI:
|
||||
//case FEATURE_ICON:
|
||||
//case FEATURE_IME:
|
||||
case FEATURE_MOUSE:
|
||||
//case FEATURE_MOUSE_WARP:
|
||||
//case FEATURE_NATIVE_DIALOG:
|
||||
//case FEATURE_NATIVE_DIALOG_INPUT:
|
||||
//case FEATURE_NATIVE_DIALOG_FILE:
|
||||
//case FEATURE_NATIVE_ICON:
|
||||
//case FEATURE_WINDOW_TRANSPARENCY:
|
||||
case FEATURE_CLIPBOARD:
|
||||
case FEATURE_KEEP_SCREEN_ON:
|
||||
case FEATURE_ORIENTATION:
|
||||
case FEATURE_TOUCHSCREEN:
|
||||
case FEATURE_VIRTUAL_KEYBOARD:
|
||||
case FEATURE_TEXT_TO_SPEECH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String DisplayServerAndroid::get_name() const {
|
||||
return "Android";
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::tts_is_speaking() const {
|
||||
return TTS_Android::is_speaking();
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::tts_is_paused() const {
|
||||
return TTS_Android::is_paused();
|
||||
}
|
||||
|
||||
TypedArray<Dictionary> DisplayServerAndroid::tts_get_voices() const {
|
||||
return TTS_Android::get_voices();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
|
||||
TTS_Android::speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::tts_pause() {
|
||||
TTS_Android::pause();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::tts_resume() {
|
||||
TTS_Android::resume();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::tts_stop() {
|
||||
TTS_Android::stop();
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::is_dark_mode_supported() const {
|
||||
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||
ERR_FAIL_NULL_V(godot_java, false);
|
||||
|
||||
return godot_java->is_dark_mode_supported();
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::is_dark_mode() const {
|
||||
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||
ERR_FAIL_NULL_V(godot_java, false);
|
||||
|
||||
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);
|
||||
|
||||
if (godot_java->has_set_clipboard()) {
|
||||
godot_java->set_clipboard(p_text);
|
||||
} else {
|
||||
DisplayServer::clipboard_set(p_text);
|
||||
}
|
||||
}
|
||||
|
||||
String DisplayServerAndroid::clipboard_get() const {
|
||||
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||
ERR_FAIL_NULL_V(godot_java, String());
|
||||
|
||||
if (godot_java->has_get_clipboard()) {
|
||||
return godot_java->get_clipboard();
|
||||
} else {
|
||||
return DisplayServer::clipboard_get();
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::clipboard_has() const {
|
||||
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||
ERR_FAIL_NULL_V(godot_java, false);
|
||||
|
||||
if (godot_java->has_has_clipboard()) {
|
||||
return godot_java->has_clipboard();
|
||||
} else {
|
||||
return DisplayServer::clipboard_has();
|
||||
}
|
||||
}
|
||||
|
||||
TypedArray<Rect2> DisplayServerAndroid::get_display_cutouts() const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL_V(godot_io_java, Array());
|
||||
return godot_io_java->get_display_cutouts();
|
||||
}
|
||||
|
||||
Rect2i DisplayServerAndroid::get_display_safe_area() const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL_V(godot_io_java, Rect2i());
|
||||
return godot_io_java->get_display_safe_area();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::screen_set_keep_on(bool p_enable) {
|
||||
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
|
||||
ERR_FAIL_NULL(godot_java);
|
||||
|
||||
godot_java->set_keep_screen_on(p_enable);
|
||||
keep_screen_on = p_enable;
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::screen_is_kept_on() const {
|
||||
return keep_screen_on;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL(godot_io_java);
|
||||
|
||||
godot_io_java->set_screen_orientation(p_orientation);
|
||||
}
|
||||
|
||||
DisplayServer::ScreenOrientation DisplayServerAndroid::screen_get_orientation(int p_screen) const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL_V(godot_io_java, SCREEN_LANDSCAPE);
|
||||
|
||||
const int orientation = godot_io_java->get_screen_orientation();
|
||||
ERR_FAIL_INDEX_V_MSG(orientation, 7, SCREEN_LANDSCAPE, "Unrecognized screen orientation");
|
||||
return (ScreenOrientation)orientation;
|
||||
}
|
||||
|
||||
int DisplayServerAndroid::get_screen_count() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DisplayServerAndroid::get_primary_screen() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point2i DisplayServerAndroid::screen_get_position(int p_screen) const {
|
||||
return Point2i(0, 0);
|
||||
}
|
||||
|
||||
Size2i DisplayServerAndroid::screen_get_size(int p_screen) const {
|
||||
return OS_Android::get_singleton()->get_display_size();
|
||||
}
|
||||
|
||||
Rect2i DisplayServerAndroid::screen_get_usable_rect(int p_screen) const {
|
||||
Size2i display_size = OS_Android::get_singleton()->get_display_size();
|
||||
return Rect2i(0, 0, display_size.width, display_size.height);
|
||||
}
|
||||
|
||||
int DisplayServerAndroid::screen_get_dpi(int p_screen) const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL_V(godot_io_java, 0);
|
||||
|
||||
return godot_io_java->get_screen_dpi();
|
||||
}
|
||||
|
||||
float DisplayServerAndroid::screen_get_scale(int p_screen) const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL_V(godot_io_java, 1.0f);
|
||||
|
||||
float screen_scale = godot_io_java->get_scaled_density();
|
||||
|
||||
// Update the scale to avoid cropping.
|
||||
Size2i screen_size = screen_get_size(p_screen);
|
||||
if (screen_size != Size2i()) {
|
||||
float width_scale = screen_size.width / (float)OS_Android::DEFAULT_WINDOW_WIDTH;
|
||||
float height_scale = screen_size.height / (float)OS_Android::DEFAULT_WINDOW_HEIGHT;
|
||||
screen_scale = MIN(screen_scale, MIN(width_scale, height_scale));
|
||||
}
|
||||
|
||||
print_line("Selected screen scale: ", screen_scale);
|
||||
return screen_scale;
|
||||
}
|
||||
|
||||
float DisplayServerAndroid::screen_get_refresh_rate(int p_screen) const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
if (!godot_io_java) {
|
||||
ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
|
||||
return SCREEN_REFRESH_RATE_FALLBACK;
|
||||
}
|
||||
|
||||
return godot_io_java->get_screen_refresh_rate(SCREEN_REFRESH_RATE_FALLBACK);
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::is_touchscreen_available() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL(godot_io_java);
|
||||
|
||||
if (godot_io_java->has_vk()) {
|
||||
godot_io_java->show_vk(p_existing_text, (int)p_type, p_max_length, p_cursor_start, p_cursor_end);
|
||||
} else {
|
||||
ERR_PRINT("Virtual keyboard not available");
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::virtual_keyboard_hide() {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL(godot_io_java);
|
||||
|
||||
if (godot_io_java->has_vk()) {
|
||||
godot_io_java->hide_vk();
|
||||
} else {
|
||||
ERR_PRINT("Virtual keyboard not available");
|
||||
}
|
||||
}
|
||||
|
||||
int DisplayServerAndroid::virtual_keyboard_get_height() const {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_NULL_V(godot_io_java, 0);
|
||||
|
||||
return godot_io_java->get_vk_height();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_window_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
|
||||
window_event_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_input_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
|
||||
input_event_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_input_text_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
|
||||
input_text_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_rect_changed_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
|
||||
rect_changed_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_drop_files_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred) const {
|
||||
if (p_callable.is_valid()) {
|
||||
if (p_deferred) {
|
||||
p_callable.call_deferred(p_arg);
|
||||
} else {
|
||||
p_callable.call(p_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::send_window_event(DisplayServer::WindowEvent p_event, bool p_deferred) const {
|
||||
_window_callback(window_event_callback, int(p_event), p_deferred);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::send_input_event(const Ref<InputEvent> &p_event) const {
|
||||
_window_callback(input_event_callback, p_event);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::send_input_text(const String &p_text) const {
|
||||
_window_callback(input_text_callback, p_text);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::_dispatch_input_events(const Ref<InputEvent> &p_event) {
|
||||
DisplayServerAndroid::get_singleton()->send_input_event(p_event);
|
||||
}
|
||||
|
||||
Vector<DisplayServer::WindowID> DisplayServerAndroid::get_window_list() const {
|
||||
Vector<WindowID> ret;
|
||||
ret.push_back(MAIN_WINDOW_ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DisplayServer::WindowID DisplayServerAndroid::get_window_at_screen_position(const Point2i &p_position) const {
|
||||
return MAIN_WINDOW_ID;
|
||||
}
|
||||
|
||||
int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const {
|
||||
ERR_FAIL_COND_V(p_window != MAIN_WINDOW_ID, 0);
|
||||
switch (p_handle_type) {
|
||||
case WINDOW_HANDLE: {
|
||||
return reinterpret_cast<int64_t>(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity());
|
||||
}
|
||||
case WINDOW_VIEW: {
|
||||
return 0; // Not supported.
|
||||
}
|
||||
#ifdef GLES3_ENABLED
|
||||
case DISPLAY_HANDLE: {
|
||||
if (rendering_driver == "opengl3") {
|
||||
return reinterpret_cast<int64_t>(eglGetCurrentDisplay());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case OPENGL_CONTEXT: {
|
||||
if (rendering_driver == "opengl3") {
|
||||
return reinterpret_cast<int64_t>(eglGetCurrentContext());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_attach_instance_id(ObjectID p_instance, DisplayServer::WindowID p_window) {
|
||||
window_attached_instance_id = p_instance;
|
||||
}
|
||||
|
||||
ObjectID DisplayServerAndroid::window_get_attached_instance_id(DisplayServer::WindowID p_window) const {
|
||||
return window_attached_instance_id;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_title(const String &p_title, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
int DisplayServerAndroid::window_get_current_screen(DisplayServer::WindowID p_window) const {
|
||||
return SCREEN_OF_MAIN_WINDOW;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_current_screen(int p_screen, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
Point2i DisplayServerAndroid::window_get_position(DisplayServer::WindowID p_window) const {
|
||||
return Point2i();
|
||||
}
|
||||
|
||||
Point2i DisplayServerAndroid::window_get_position_with_decorations(DisplayServer::WindowID p_window) const {
|
||||
return Point2i();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_position(const Point2i &p_position, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_transient(DisplayServer::WindowID p_window, DisplayServer::WindowID p_parent) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_max_size(const Size2i p_size, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
Size2i DisplayServerAndroid::window_get_max_size(DisplayServer::WindowID p_window) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_min_size(const Size2i p_size, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
Size2i DisplayServerAndroid::window_get_min_size(DisplayServer::WindowID p_window) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_size(const Size2i p_size, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
Size2i DisplayServerAndroid::window_get_size(DisplayServer::WindowID p_window) const {
|
||||
return OS_Android::get_singleton()->get_display_size();
|
||||
}
|
||||
|
||||
Size2i DisplayServerAndroid::window_get_size_with_decorations(DisplayServer::WindowID p_window) const {
|
||||
return OS_Android::get_singleton()->get_display_size();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_mode(DisplayServer::WindowMode p_mode, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
DisplayServer::WindowMode DisplayServerAndroid::window_get_mode(DisplayServer::WindowID p_window) const {
|
||||
return WINDOW_MODE_FULLSCREEN;
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::window_is_maximize_allowed(DisplayServer::WindowID p_window) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_flag(DisplayServer::WindowFlags p_flag, bool p_enabled, DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::window_get_flag(DisplayServer::WindowFlags p_flag, DisplayServer::WindowID p_window) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_request_attention(DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_move_to_foreground(DisplayServer::WindowID p_window) {
|
||||
// Not supported on Android.
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::window_is_focused(WindowID p_window) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::window_can_draw(DisplayServer::WindowID p_window) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::can_any_window_draw() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::process_events() {
|
||||
Input::get_singleton()->flush_buffered_events();
|
||||
}
|
||||
|
||||
Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
|
||||
Vector<String> drivers;
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
drivers.push_back("opengl3");
|
||||
#endif
|
||||
#ifdef VULKAN_ENABLED
|
||||
drivers.push_back("vulkan");
|
||||
#endif
|
||||
|
||||
return drivers;
|
||||
}
|
||||
|
||||
DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
|
||||
DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error));
|
||||
if (r_error != OK) {
|
||||
if (p_rendering_driver == "vulkan") {
|
||||
OS::get_singleton()->alert(
|
||||
"Your device seems not to support the required Vulkan version.\n\n"
|
||||
"Please try exporting your game using the 'gl_compatibility' renderer.",
|
||||
"Unable to initialize Vulkan video driver");
|
||||
} else {
|
||||
OS::get_singleton()->alert(
|
||||
"Your device seems not to support the required OpenGL ES 3.0 version.",
|
||||
"Unable to initialize OpenGL video driver");
|
||||
}
|
||||
}
|
||||
return ds;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::register_android_driver() {
|
||||
register_create_function("android", create_func, get_rendering_drivers_func);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::reset_window() {
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
if (rendering_device) {
|
||||
rendering_device->screen_free(MAIN_WINDOW_ID);
|
||||
}
|
||||
|
||||
VSyncMode last_vsync_mode = rendering_context->window_get_vsync_mode(MAIN_WINDOW_ID);
|
||||
rendering_context->window_destroy(MAIN_WINDOW_ID);
|
||||
|
||||
union {
|
||||
#ifdef VULKAN_ENABLED
|
||||
RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan;
|
||||
#endif
|
||||
} wpd;
|
||||
#ifdef VULKAN_ENABLED
|
||||
if (rendering_driver == "vulkan") {
|
||||
ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
|
||||
ERR_FAIL_NULL(native_window);
|
||||
wpd.vulkan.window = native_window;
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
|
||||
if (rect_changed_callback.is_valid()) {
|
||||
rect_changed_callback.call(Rect2i(0, 0, p_width, p_height));
|
||||
}
|
||||
}
|
||||
|
||||
DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
|
||||
rendering_driver = p_rendering_driver;
|
||||
|
||||
keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on");
|
||||
|
||||
native_menu = memnew(NativeMenu);
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
if (rendering_driver == "opengl3") {
|
||||
RasterizerGLES3::make_current(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
rendering_context = nullptr;
|
||||
rendering_device = nullptr;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
if (rendering_driver == "vulkan") {
|
||||
rendering_context = memnew(RenderingContextDriverVulkanAndroid);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rendering_context) {
|
||||
if (rendering_context->initialize() != OK) {
|
||||
ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
union {
|
||||
#ifdef VULKAN_ENABLED
|
||||
RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan;
|
||||
#endif
|
||||
} wpd;
|
||||
#ifdef VULKAN_ENABLED
|
||||
if (rendering_driver == "vulkan") {
|
||||
ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
|
||||
ERR_FAIL_NULL(native_window);
|
||||
wpd.vulkan.window = native_window;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
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);
|
||||
if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) {
|
||||
rendering_device = nullptr;
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
rendering_device->screen_create(MAIN_WINDOW_ID);
|
||||
|
||||
RendererCompositorRD::make_current();
|
||||
}
|
||||
#endif
|
||||
|
||||
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
|
||||
|
||||
r_error = OK;
|
||||
}
|
||||
|
||||
DisplayServerAndroid::~DisplayServerAndroid() {
|
||||
if (native_menu) {
|
||||
memdelete(native_menu);
|
||||
native_menu = nullptr;
|
||||
}
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_device) {
|
||||
memdelete(rendering_device);
|
||||
}
|
||||
if (rendering_context) {
|
||||
memdelete(rendering_context);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::process_accelerometer(const Vector3 &p_accelerometer) {
|
||||
Input::get_singleton()->set_accelerometer(p_accelerometer);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::process_gravity(const Vector3 &p_gravity) {
|
||||
Input::get_singleton()->set_gravity(p_gravity);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::process_magnetometer(const Vector3 &p_magnetometer) {
|
||||
Input::get_singleton()->set_magnetometer(p_magnetometer);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) {
|
||||
Input::get_singleton()->set_gyroscope(p_gyroscope);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) {
|
||||
if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon() || !OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_capture_pointer()) {
|
||||
return;
|
||||
}
|
||||
if (mouse_mode == p_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_mode == MouseMode::MOUSE_MODE_HIDDEN) {
|
||||
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->set_pointer_icon(CURSOR_TYPE_NULL);
|
||||
} else {
|
||||
cursor_set_shape(cursor_shape);
|
||||
}
|
||||
|
||||
if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) {
|
||||
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture();
|
||||
} else {
|
||||
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->release_pointer_capture();
|
||||
}
|
||||
|
||||
mouse_mode = p_mode;
|
||||
}
|
||||
|
||||
DisplayServer::MouseMode DisplayServerAndroid::mouse_get_mode() const {
|
||||
return mouse_mode;
|
||||
}
|
||||
|
||||
Point2i DisplayServerAndroid::mouse_get_position() const {
|
||||
return Input::get_singleton()->get_mouse_position();
|
||||
}
|
||||
|
||||
BitField<MouseButtonMask> DisplayServerAndroid::mouse_get_button_state() const {
|
||||
return Input::get_singleton()->get_mouse_button_mask();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::_cursor_set_shape_helper(CursorShape p_shape, bool force) {
|
||||
if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon()) {
|
||||
return;
|
||||
}
|
||||
if (cursor_shape == p_shape && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor_shape = p_shape;
|
||||
|
||||
if (mouse_mode == MouseMode::MOUSE_MODE_VISIBLE || mouse_mode == MouseMode::MOUSE_MODE_CONFINED) {
|
||||
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->set_pointer_icon(android_cursors[cursor_shape]);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) {
|
||||
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
|
||||
_cursor_set_shape_helper(p_shape);
|
||||
}
|
||||
|
||||
DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const {
|
||||
return cursor_shape;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
|
||||
String cursor_path = p_cursor.is_valid() ? p_cursor->get_path() : "";
|
||||
if (!cursor_path.is_empty()) {
|
||||
cursor_path = ProjectSettings::get_singleton()->globalize_path(cursor_path);
|
||||
}
|
||||
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->configure_pointer_icon(android_cursors[cursor_shape], cursor_path, p_hotspot);
|
||||
_cursor_set_shape_helper(p_shape, true);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||
#if defined(RD_ENABLED)
|
||||
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 (rendering_context) {
|
||||
return rendering_context->window_get_vsync_mode(p_window);
|
||||
}
|
||||
#endif
|
||||
return DisplayServer::VSYNC_ENABLED;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::reset_swap_buffers_flag() {
|
||||
swap_buffers_flag = false;
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::should_swap_buffers() const {
|
||||
return swap_buffers_flag;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::swap_buffers() {
|
||||
swap_buffers_flag = true;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::set_native_icon(const String &p_filename) {
|
||||
// NOT SUPPORTED
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::set_icon(const Ref<Image> &p_icon) {
|
||||
// NOT SUPPORTED
|
||||
}
|
||||
235
engine/platform/android/display_server_android.h
Normal file
235
engine/platform/android/display_server_android.h
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/**************************************************************************/
|
||||
/* display_server_android.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISPLAY_SERVER_ANDROID_H
|
||||
#define DISPLAY_SERVER_ANDROID_H
|
||||
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
class RenderingContextDriver;
|
||||
class RenderingDevice;
|
||||
#endif
|
||||
|
||||
class DisplayServerAndroid : public DisplayServer {
|
||||
// No need to register with GDCLASS, it's platform-specific and nothing is added.
|
||||
|
||||
String rendering_driver;
|
||||
|
||||
// https://developer.android.com/reference/android/view/PointerIcon
|
||||
// mapping between Godot's cursor shape to Android's'
|
||||
int android_cursors[CURSOR_MAX] = {
|
||||
1000, //CURSOR_ARROW
|
||||
1008, //CURSOR_IBEAM
|
||||
1002, //CURSOR_POINTIN
|
||||
1007, //CURSOR_CROSS
|
||||
1004, //CURSOR_WAIT
|
||||
1004, //CURSOR_BUSY
|
||||
1021, //CURSOR_DRAG
|
||||
1021, //CURSOR_CAN_DRO
|
||||
1000, //CURSOR_FORBIDD (no corresponding icon in Android's icon so fallback to default)
|
||||
1015, //CURSOR_VSIZE
|
||||
1014, //CURSOR_HSIZE
|
||||
1017, //CURSOR_BDIAGSI
|
||||
1016, //CURSOR_FDIAGSI
|
||||
1020, //CURSOR_MOVE
|
||||
1015, //CURSOR_VSPLIT
|
||||
1014, //CURSOR_HSPLIT
|
||||
1003, //CURSOR_HELP
|
||||
};
|
||||
const int CURSOR_TYPE_NULL = 0;
|
||||
MouseMode mouse_mode = MouseMode::MOUSE_MODE_VISIBLE;
|
||||
|
||||
bool keep_screen_on;
|
||||
bool swap_buffers_flag;
|
||||
|
||||
CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
RenderingContextDriver *rendering_context = nullptr;
|
||||
RenderingDevice *rendering_device = nullptr;
|
||||
#endif
|
||||
NativeMenu *native_menu = nullptr;
|
||||
|
||||
ObjectID window_attached_instance_id;
|
||||
|
||||
Callable window_event_callback;
|
||||
Callable input_event_callback;
|
||||
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);
|
||||
|
||||
public:
|
||||
static DisplayServerAndroid *get_singleton();
|
||||
|
||||
virtual bool has_feature(Feature p_feature) const override;
|
||||
virtual String get_name() const override;
|
||||
|
||||
virtual bool tts_is_speaking() const override;
|
||||
virtual bool tts_is_paused() const override;
|
||||
virtual TypedArray<Dictionary> tts_get_voices() const override;
|
||||
|
||||
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
|
||||
virtual void tts_pause() override;
|
||||
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;
|
||||
virtual bool clipboard_has() const override;
|
||||
|
||||
virtual TypedArray<Rect2> get_display_cutouts() const override;
|
||||
virtual Rect2i get_display_safe_area() const override;
|
||||
|
||||
virtual void screen_set_keep_on(bool p_enable) override;
|
||||
virtual bool screen_is_kept_on() const override;
|
||||
|
||||
virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override;
|
||||
virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
|
||||
virtual int get_screen_count() const override;
|
||||
virtual int get_primary_screen() const override;
|
||||
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual bool is_touchscreen_available() const override;
|
||||
|
||||
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
|
||||
virtual void virtual_keyboard_hide() override;
|
||||
virtual int virtual_keyboard_get_height() const override;
|
||||
|
||||
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
void send_window_event(WindowEvent p_event, bool p_deferred = false) const;
|
||||
void send_input_event(const Ref<InputEvent> &p_event) const;
|
||||
void send_input_text(const String &p_text) const;
|
||||
|
||||
virtual Vector<WindowID> get_window_list() const override;
|
||||
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;
|
||||
|
||||
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual Point2i window_get_position_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual void window_set_transient(WindowID p_window, WindowID p_parent) override;
|
||||
|
||||
virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual Size2i window_get_size_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool can_any_window_draw() const override;
|
||||
|
||||
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
|
||||
|
||||
virtual void process_events() override;
|
||||
|
||||
void process_accelerometer(const Vector3 &p_accelerometer);
|
||||
void process_gravity(const Vector3 &p_gravity);
|
||||
void process_magnetometer(const Vector3 &p_magnetometer);
|
||||
void process_gyroscope(const Vector3 &p_gyroscope);
|
||||
|
||||
void _cursor_set_shape_helper(CursorShape p_shape, bool force = false);
|
||||
virtual void cursor_set_shape(CursorShape p_shape) override;
|
||||
virtual CursorShape cursor_get_shape() const override;
|
||||
virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
|
||||
|
||||
virtual void mouse_set_mode(MouseMode p_mode) override;
|
||||
virtual MouseMode mouse_get_mode() const override;
|
||||
|
||||
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);
|
||||
static Vector<String> get_rendering_drivers_func();
|
||||
static void register_android_driver();
|
||||
|
||||
void reset_window();
|
||||
void notify_surface_changed(int p_width, int p_height);
|
||||
|
||||
virtual Point2i mouse_get_position() const override;
|
||||
virtual BitField<MouseButtonMask> mouse_get_button_state() const override;
|
||||
|
||||
void reset_swap_buffers_flag();
|
||||
bool should_swap_buffers() const;
|
||||
virtual void swap_buffers() override;
|
||||
|
||||
virtual void set_native_icon(const String &p_filename) override;
|
||||
virtual void set_icon(const Ref<Image> &p_icon) override;
|
||||
|
||||
DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);
|
||||
~DisplayServerAndroid();
|
||||
};
|
||||
|
||||
#endif // DISPLAY_SERVER_ANDROID_H
|
||||
|
|
@ -0,0 +1,604 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorExportPlatformAndroid" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Exporter for Android.
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Exporting for Android">$DOCS_URL/tutorials/export/exporting_for_android.html</link>
|
||||
<link title="Gradle builds for Android">$DOCS_URL/tutorials/export/android_gradle_build.html</link>
|
||||
<link title="Android plugins documentation index">$DOCS_URL/tutorials/platform/index.html</link>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="apk_expansion/SALT" type="String" setter="" getter="">
|
||||
Array of random bytes that the licensing Policy uses to create an [url=https://developer.android.com/google/play/licensing/adding-licensing#impl-Obfuscator]Obfuscator[/url].
|
||||
</member>
|
||||
<member name="apk_expansion/enable" type="bool" setter="" getter="">
|
||||
If [code]true[/code], project resources are stored in the separate APK expansion file, instead of the APK.
|
||||
[b]Note:[/b] APK expansion should be enabled to use PCK encryption. See [url=https://developer.android.com/google/play/expansion-files]APK Expansion Files[/url]
|
||||
</member>
|
||||
<member name="apk_expansion/public_key" type="String" setter="" getter="">
|
||||
Base64 encoded RSA public key for your publisher account, available from the profile page on the "Google Play Console".
|
||||
</member>
|
||||
<member name="architectures/arm64-v8a" type="bool" setter="" getter="">
|
||||
If [code]true[/code], [code]arm64[/code] binaries are included into exported project.
|
||||
</member>
|
||||
<member name="architectures/armeabi-v7a" type="bool" setter="" getter="">
|
||||
If [code]true[/code], [code]arm32[/code] binaries are included into exported project.
|
||||
</member>
|
||||
<member name="architectures/x86" type="bool" setter="" getter="">
|
||||
If [code]true[/code], [code]x86_32[/code] binaries are included into exported project.
|
||||
</member>
|
||||
<member name="architectures/x86_64" type="bool" setter="" getter="">
|
||||
If [code]true[/code], [code]x86_64[/code] binaries are included into exported project.
|
||||
</member>
|
||||
<member name="command_line/extra_args" type="String" setter="" getter="">
|
||||
A list of additional command line arguments, separated by space, which the exported project will receive when started.
|
||||
</member>
|
||||
<member name="custom_template/debug" type="String" setter="" getter="">
|
||||
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 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="">
|
||||
Application export format (*.apk or *.aab).
|
||||
</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="">
|
||||
Minimum Android API level required for the application to run (used during Gradle build). See [url=https://developer.android.com/guide/topics/manifest/uses-sdk-element#uses]android:minSdkVersion[/url].
|
||||
</member>
|
||||
<member name="gradle_build/target_sdk" type="String" setter="" getter="">
|
||||
The Android API level on which the application is designed to run (used during Gradle build). See [url=https://developer.android.com/guide/topics/manifest/uses-sdk-element#uses]android:targetSdkVersion[/url].
|
||||
</member>
|
||||
<member name="gradle_build/use_gradle_build" type="bool" setter="" getter="">
|
||||
If [code]true[/code], Gradle build is used instead of pre-built APK.
|
||||
</member>
|
||||
<member name="graphics/opengl_debug" type="bool" setter="" getter="">
|
||||
If [code]true[/code], OpenGL ES debug context will be created (additional runtime checking, validation, and logging).
|
||||
</member>
|
||||
<member name="keystore/debug" type="String" setter="" getter="">
|
||||
Path of the debug keystore file.
|
||||
Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PATH[/code].
|
||||
Fallbacks to [code]EditorSettings.export/android/debug_keystore[/code] if empty.
|
||||
</member>
|
||||
<member name="keystore/debug_password" type="String" setter="" getter="">
|
||||
Password for the debug keystore file.
|
||||
Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD[/code].
|
||||
Fallbacks to [code]EditorSettings.export/android/debug_keystore_pass[/code] if both it and [member keystore/debug] are empty.
|
||||
</member>
|
||||
<member name="keystore/debug_user" type="String" setter="" getter="">
|
||||
User name for the debug keystore file.
|
||||
Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_USER[/code].
|
||||
Fallbacks to [code]EditorSettings.export/android/debug_keystore_user[/code] if both it and [member keystore/debug] are empty.
|
||||
</member>
|
||||
<member name="keystore/release" type="String" setter="" getter="">
|
||||
Path of the release keystore file.
|
||||
Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PATH[/code].
|
||||
</member>
|
||||
<member name="keystore/release_password" type="String" setter="" getter="">
|
||||
Password for the release keystore file.
|
||||
Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD[/code].
|
||||
</member>
|
||||
<member name="keystore/release_user" type="String" setter="" getter="">
|
||||
User name for the release keystore file.
|
||||
Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_USER[/code].
|
||||
</member>
|
||||
<member name="launcher_icons/adaptive_background_432x432" type="String" setter="" getter="">
|
||||
Background layer of the application adaptive icon file. See [url=https://developer.android.com/develop/ui/views/launch/icon_design_adaptive#design-adaptive-icons]Design adaptive icons[/url].
|
||||
</member>
|
||||
<member name="launcher_icons/adaptive_foreground_432x432" type="String" setter="" getter="">
|
||||
Foreground layer of the application adaptive icon file. See [url=https://developer.android.com/develop/ui/views/launch/icon_design_adaptive#design-adaptive-icons]Design adaptive icons[/url].
|
||||
</member>
|
||||
<member name="launcher_icons/main_192x192" type="String" setter="" getter="">
|
||||
Application icon file. If left empty, it will fallback to [member ProjectSettings.application/config/icon].
|
||||
</member>
|
||||
<member name="package/app_category" type="int" setter="" getter="">
|
||||
Application category for the Google Play Store. Only define this if your application fits one of the categories well. See [url=https://developer.android.com/guide/topics/manifest/application-element#appCategory]android:appCategory[/url].
|
||||
</member>
|
||||
<member name="package/exclude_from_recents" type="bool" setter="" getter="">
|
||||
If [code]true[/code], task initiated by main activity will be excluded from the list of recently used applications. See [url=https://developer.android.com/guide/topics/manifest/activity-element#exclude]android:excludeFromRecents[/url].
|
||||
</member>
|
||||
<member name="package/name" type="String" setter="" getter="">
|
||||
Name of the application.
|
||||
</member>
|
||||
<member name="package/retain_data_on_uninstall" type="bool" setter="" getter="">
|
||||
If [code]true[/code], when the user uninstalls an app, a prompt to keep the app's data will be shown. See [url=https://developer.android.com/guide/topics/manifest/application-element#fragileuserdata]android:hasFragileUserData[/url].
|
||||
</member>
|
||||
<member name="package/show_as_launcher_app" type="bool" setter="" getter="">
|
||||
If [code]true[/code], the user will be able to set this app as the system launcher in Android preferences.
|
||||
</member>
|
||||
<member name="package/show_in_android_tv" type="bool" setter="" getter="">
|
||||
If [code]true[/code], this app will show in Android TV launcher UI.
|
||||
</member>
|
||||
<member name="package/show_in_app_library" type="bool" setter="" getter="">
|
||||
If [code]true[/code], this app will show in the device's app library.
|
||||
[b]Note:[/b] This is [code]true[/code] by default.
|
||||
</member>
|
||||
<member name="package/signed" type="bool" setter="" getter="">
|
||||
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. 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].
|
||||
</member>
|
||||
<member name="permissions/access_coarse_location" type="bool" setter="" getter="">
|
||||
Allows access to the approximate location information. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION]ACCESS_COARSE_LOCATION[/url].
|
||||
</member>
|
||||
<member name="permissions/access_fine_location" type="bool" setter="" getter="">
|
||||
Allows access to the precise location information. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION]ACCESS_FINE_LOCATION[/url].
|
||||
</member>
|
||||
<member name="permissions/access_location_extra_commands" type="bool" setter="" getter="">
|
||||
Allows access to the extra location provider commands. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_LOCATION_EXTRA_COMMANDS]ACCESS_LOCATION_EXTRA_COMMANDS[/url].
|
||||
</member>
|
||||
<member name="permissions/access_mock_location" type="bool" setter="" getter="">
|
||||
Allows an application to create mock location providers for testing.
|
||||
</member>
|
||||
<member name="permissions/access_network_state" type="bool" setter="" getter="">
|
||||
Allows access to the information about networks. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_NETWORK_STATE]ACCESS_NETWORK_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/access_surface_flinger" type="bool" setter="" getter="">
|
||||
Allows an application to use SurfaceFlinger's low level features.
|
||||
</member>
|
||||
<member name="permissions/access_wifi_state" type="bool" setter="" getter="">
|
||||
Allows access to the information about Wi-Fi networks. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_WIFI_STATE]ACCESS_WIFI_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/account_manager" type="bool" setter="" getter="">
|
||||
Allows applications to call into AccountAuthenticators. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCOUNT_MANAGER]ACCOUNT_MANAGER[/url].
|
||||
</member>
|
||||
<member name="permissions/add_voicemail" type="bool" setter="" getter="">
|
||||
Allows an application to add voicemails into the system. See [url=https://developer.android.com/reference/android/Manifest.permission#ADD_VOICEMAIL]ADD_VOICEMAIL[/url].
|
||||
</member>
|
||||
<member name="permissions/authenticate_accounts" type="bool" setter="" getter="">
|
||||
Allows an application to act as an AccountAuthenticator for the AccountManager.
|
||||
</member>
|
||||
<member name="permissions/battery_stats" type="bool" setter="" getter="">
|
||||
Allows an application to collect battery statistics. See [url=https://developer.android.com/reference/android/Manifest.permission#BATTERY_STATS]BATTERY_STATS[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_accessibility_service" type="bool" setter="" getter="">
|
||||
Must be required by an AccessibilityService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_ACCESSIBILITY_SERVICE]BIND_ACCESSIBILITY_SERVICE[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_appwidget" type="bool" setter="" getter="">
|
||||
Allows an application to tell the AppWidget service which application can access AppWidget's data. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_APPWIDGET]BIND_APPWIDGET[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_device_admin" type="bool" setter="" getter="">
|
||||
Must be required by device administration receiver, to ensure that only the system can interact with it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_DEVICE_ADMIN]BIND_DEVICE_ADMIN[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_input_method" type="bool" setter="" getter="">
|
||||
Must be required by an InputMethodService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_INPUT_METHOD]BIND_INPUT_METHOD[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_nfc_service" type="bool" setter="" getter="">
|
||||
Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NFC_SERVICE]BIND_NFC_SERVICE[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_notification_listener_service" type="bool" setter="" getter="">
|
||||
Must be required by a NotificationListenerService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE]BIND_NOTIFICATION_LISTENER_SERVICE[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_print_service" type="bool" setter="" getter="">
|
||||
Must be required by a PrintService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_PRINT_SERVICE]BIND_PRINT_SERVICE[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_remoteviews" type="bool" setter="" getter="">
|
||||
Must be required by a RemoteViewsService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_REMOTEVIEWS]BIND_REMOTEVIEWS[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_text_service" type="bool" setter="" getter="">
|
||||
Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_TEXT_SERVICE]BIND_TEXT_SERVICE[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_vpn_service" type="bool" setter="" getter="">
|
||||
Must be required by a VpnService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_VPN_SERVICE]BIND_VPN_SERVICE[/url].
|
||||
</member>
|
||||
<member name="permissions/bind_wallpaper" type="bool" setter="" getter="">
|
||||
Must be required by a WallpaperService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_WALLPAPER]BIND_WALLPAPER[/url].
|
||||
</member>
|
||||
<member name="permissions/bluetooth" type="bool" setter="" getter="">
|
||||
Allows applications to connect to paired bluetooth devices. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH]BLUETOOTH[/url].
|
||||
</member>
|
||||
<member name="permissions/bluetooth_admin" type="bool" setter="" getter="">
|
||||
Allows applications to discover and pair bluetooth devices. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_ADMIN]BLUETOOTH_ADMIN[/url].
|
||||
</member>
|
||||
<member name="permissions/bluetooth_privileged" type="bool" setter="" getter="">
|
||||
Allows applications to pair bluetooth devices without user interaction, and to allow or disallow phonebook access or message access. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_PRIVILEGED]BLUETOOTH_PRIVILEGED[/url].
|
||||
</member>
|
||||
<member name="permissions/brick" type="bool" setter="" getter="">
|
||||
Required to be able to disable the device (very dangerous!).
|
||||
</member>
|
||||
<member name="permissions/broadcast_package_removed" type="bool" setter="" getter="">
|
||||
Allows an application to broadcast a notification that an application package has been removed. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_PACKAGE_REMOVED]BROADCAST_PACKAGE_REMOVED[/url].
|
||||
</member>
|
||||
<member name="permissions/broadcast_sms" type="bool" setter="" getter="">
|
||||
Allows an application to broadcast an SMS receipt notification. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_SMS]BROADCAST_SMS[/url].
|
||||
</member>
|
||||
<member name="permissions/broadcast_sticky" type="bool" setter="" getter="">
|
||||
Allows an application to broadcast sticky intents. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_STICKY]BROADCAST_STICKY[/url].
|
||||
</member>
|
||||
<member name="permissions/broadcast_wap_push" type="bool" setter="" getter="">
|
||||
Allows an application to broadcast a WAP PUSH receipt notification. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_WAP_PUSH]BROADCAST_WAP_PUSH[/url].
|
||||
</member>
|
||||
<member name="permissions/call_phone" type="bool" setter="" getter="">
|
||||
Allows an application to initiate a phone call without going through the Dialer user interface. See [url=https://developer.android.com/reference/android/Manifest.permission#CALL_PHONE]CALL_PHONE[/url].
|
||||
</member>
|
||||
<member name="permissions/call_privileged" type="bool" setter="" getter="">
|
||||
Allows an application to call any phone number, including emergency numbers, without going through the Dialer user interface. See [url=https://developer.android.com/reference/android/Manifest.permission#CALL_PRIVILEGED]CALL_PRIVILEGED[/url].
|
||||
</member>
|
||||
<member name="permissions/camera" type="bool" setter="" getter="">
|
||||
Required to be able to access the camera device. See [url=https://developer.android.com/reference/android/Manifest.permission#CAMERA]CAMERA[/url].
|
||||
</member>
|
||||
<member name="permissions/capture_audio_output" type="bool" setter="" getter="">
|
||||
Allows an application to capture audio output. See [url=https://developer.android.com/reference/android/Manifest.permission#CAPTURE_AUDIO_OUTPUT]CAPTURE_AUDIO_OUTPUT[/url].
|
||||
</member>
|
||||
<member name="permissions/capture_secure_video_output" type="bool" setter="" getter="">
|
||||
Allows an application to capture secure video output.
|
||||
</member>
|
||||
<member name="permissions/capture_video_output" type="bool" setter="" getter="">
|
||||
Allows an application to capture video output.
|
||||
</member>
|
||||
<member name="permissions/change_component_enabled_state" type="bool" setter="" getter="">
|
||||
Allows an application to change whether an application component (other than its own) is enabled or not. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_COMPONENT_ENABLED_STATE]CHANGE_COMPONENT_ENABLED_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/change_configuration" type="bool" setter="" getter="">
|
||||
Allows an application to modify the current configuration, such as locale. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_CONFIGURATION]CHANGE_CONFIGURATION[/url].
|
||||
</member>
|
||||
<member name="permissions/change_network_state" type="bool" setter="" getter="">
|
||||
Allows applications to change network connectivity state. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_NETWORK_STATE]CHANGE_NETWORK_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/change_wifi_multicast_state" type="bool" setter="" getter="">
|
||||
Allows applications to enter Wi-Fi Multicast mode. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_WIFI_MULTICAST_STATE]CHANGE_WIFI_MULTICAST_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/change_wifi_state" type="bool" setter="" getter="">
|
||||
Allows applications to change Wi-Fi connectivity state. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_WIFI_STATE]CHANGE_WIFI_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/clear_app_cache" type="bool" setter="" getter="">
|
||||
Allows an application to clear the caches of all installed applications on the device. See [url=https://developer.android.com/reference/android/Manifest.permission#CLEAR_APP_CACHE]CLEAR_APP_CACHE[/url].
|
||||
</member>
|
||||
<member name="permissions/clear_app_user_data" type="bool" setter="" getter="">
|
||||
Allows an application to clear user data.
|
||||
</member>
|
||||
<member name="permissions/control_location_updates" type="bool" setter="" getter="">
|
||||
Allows enabling/disabling location update notifications from the radio. See [url=https://developer.android.com/reference/android/Manifest.permission#CONTROL_LOCATION_UPDATES]CONTROL_LOCATION_UPDATES[/url].
|
||||
</member>
|
||||
<member name="permissions/custom_permissions" type="PackedStringArray" setter="" getter="">
|
||||
Array of custom permission strings.
|
||||
</member>
|
||||
<member name="permissions/delete_cache_files" type="bool" setter="" getter="" deprecated="">
|
||||
</member>
|
||||
<member name="permissions/delete_packages" type="bool" setter="" getter="">
|
||||
Allows an application to delete packages. See [url=https://developer.android.com/reference/android/Manifest.permission#DELETE_PACKAGES]DELETE_PACKAGES[/url].
|
||||
</member>
|
||||
<member name="permissions/device_power" type="bool" setter="" getter="">
|
||||
Allows low-level access to power management.
|
||||
</member>
|
||||
<member name="permissions/diagnostic" type="bool" setter="" getter="">
|
||||
Allows applications to RW to diagnostic resources. See [url=https://developer.android.com/reference/android/Manifest.permission#DIAGNOSTIC]DIAGNOSTIC[/url].
|
||||
</member>
|
||||
<member name="permissions/disable_keyguard" type="bool" setter="" getter="">
|
||||
Allows applications to disable the keyguard if it is not secure. See [url=https://developer.android.com/reference/android/Manifest.permission#DISABLE_KEYGUARD]DISABLE_KEYGUARD[/url].
|
||||
</member>
|
||||
<member name="permissions/dump" type="bool" setter="" getter="">
|
||||
Allows an application to retrieve state dump information from system services. See [url=https://developer.android.com/reference/android/Manifest.permission#DUMP]DUMP[/url].
|
||||
</member>
|
||||
<member name="permissions/expand_status_bar" type="bool" setter="" getter="">
|
||||
Allows an application to expand or collapse the status bar. See [url=https://developer.android.com/reference/android/Manifest.permission#EXPAND_STATUS_BAR]EXPAND_STATUS_BAR[/url].
|
||||
</member>
|
||||
<member name="permissions/factory_test" type="bool" setter="" getter="">
|
||||
Run as a manufacturer test application, running as the root user. See [url=https://developer.android.com/reference/android/Manifest.permission#FACTORY_TEST]FACTORY_TEST[/url].
|
||||
</member>
|
||||
<member name="permissions/flashlight" type="bool" setter="" getter="">
|
||||
Allows access to the flashlight.
|
||||
</member>
|
||||
<member name="permissions/force_back" type="bool" setter="" getter="">
|
||||
Allows an application to force a BACK operation on whatever is the top activity.
|
||||
</member>
|
||||
<member name="permissions/get_accounts" type="bool" setter="" getter="">
|
||||
Allows access to the list of accounts in the Accounts Service. See [url=https://developer.android.com/reference/android/Manifest.permission#GET_ACCOUNTS]GET_ACCOUNTS[/url].
|
||||
</member>
|
||||
<member name="permissions/get_package_size" type="bool" setter="" getter="">
|
||||
Allows an application to find out the space used by any package. See [url=https://developer.android.com/reference/android/Manifest.permission#GET_PACKAGE_SIZE]GET_PACKAGE_SIZE[/url].
|
||||
</member>
|
||||
<member name="permissions/get_tasks" type="bool" setter="" getter="" deprecated="Deprecated in API level 21.">
|
||||
</member>
|
||||
<member name="permissions/get_top_activity_info" type="bool" setter="" getter="">
|
||||
Allows an application to retrieve private information about the current top activity.
|
||||
</member>
|
||||
<member name="permissions/global_search" type="bool" setter="" getter="">
|
||||
Used on content providers to allow the global search system to access their data. See [url=https://developer.android.com/reference/android/Manifest.permission#GLOBAL_SEARCH]GLOBAL_SEARCH[/url].
|
||||
</member>
|
||||
<member name="permissions/hardware_test" type="bool" setter="" getter="">
|
||||
Allows access to hardware peripherals.
|
||||
</member>
|
||||
<member name="permissions/inject_events" type="bool" setter="" getter="">
|
||||
Allows an application to inject user events (keys, touch, trackball) into the event stream and deliver them to ANY window.
|
||||
</member>
|
||||
<member name="permissions/install_location_provider" type="bool" setter="" getter="">
|
||||
Allows an application to install a location provider into the Location Manager. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_LOCATION_PROVIDER]INSTALL_LOCATION_PROVIDER[/url].
|
||||
</member>
|
||||
<member name="permissions/install_packages" type="bool" setter="" getter="">
|
||||
Allows an application to install packages. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_PACKAGES]INSTALL_PACKAGES[/url].
|
||||
</member>
|
||||
<member name="permissions/install_shortcut" type="bool" setter="" getter="">
|
||||
Allows an application to install a shortcut in Launcher. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_SHORTCUT]INSTALL_SHORTCUT[/url].
|
||||
</member>
|
||||
<member name="permissions/internal_system_window" type="bool" setter="" getter="">
|
||||
Allows an application to open windows that are for use by parts of the system user interface.
|
||||
</member>
|
||||
<member name="permissions/internet" type="bool" setter="" getter="">
|
||||
Allows applications to open network sockets. See [url=https://developer.android.com/reference/android/Manifest.permission#INTERNET]INTERNET[/url].
|
||||
</member>
|
||||
<member name="permissions/kill_background_processes" type="bool" setter="" getter="">
|
||||
Allows an application to call ActivityManager.killBackgroundProcesses(String). See [url=https://developer.android.com/reference/android/Manifest.permission#KILL_BACKGROUND_PROCESSES]KILL_BACKGROUND_PROCESSES[/url].
|
||||
</member>
|
||||
<member name="permissions/location_hardware" type="bool" setter="" getter="">
|
||||
Allows an application to use location features in hardware, such as the geofencing api. See [url=https://developer.android.com/reference/android/Manifest.permission#LOCATION_HARDWARE]LOCATION_HARDWARE[/url].
|
||||
</member>
|
||||
<member name="permissions/manage_accounts" type="bool" setter="" getter="">
|
||||
Allows an application to manage the list of accounts in the AccountManager.
|
||||
</member>
|
||||
<member name="permissions/manage_app_tokens" type="bool" setter="" getter="">
|
||||
Allows an application to manage (create, destroy, Z-order) application tokens in the window manager.
|
||||
</member>
|
||||
<member name="permissions/manage_documents" type="bool" setter="" getter="">
|
||||
Allows an application to manage access to documents, usually as part of a document picker. See [url=https://developer.android.com/reference/android/Manifest.permission#MANAGE_DOCUMENTS]MANAGE_DOCUMENTS[/url].
|
||||
</member>
|
||||
<member name="permissions/manage_external_storage" type="bool" setter="" getter="">
|
||||
Allows an application a broad access to external storage in scoped storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MANAGE_EXTERNAL_STORAGE]MANAGE_EXTERNAL_STORAGE[/url].
|
||||
</member>
|
||||
<member name="permissions/master_clear" type="bool" setter="" getter="">
|
||||
See [url=https://developer.android.com/reference/android/Manifest.permission#MASTER_CLEAR]MASTER_CLEAR[/url].
|
||||
</member>
|
||||
<member name="permissions/media_content_control" type="bool" setter="" getter="">
|
||||
Allows an application to know what content is playing and control its playback. See [url=https://developer.android.com/reference/android/Manifest.permission#MEDIA_CONTENT_CONTROL]MEDIA_CONTENT_CONTROL[/url].
|
||||
</member>
|
||||
<member name="permissions/modify_audio_settings" type="bool" setter="" getter="">
|
||||
Allows an application to modify global audio settings. See [url=https://developer.android.com/reference/android/Manifest.permission#MODIFY_AUDIO_SETTINGS]MODIFY_AUDIO_SETTINGS[/url].
|
||||
</member>
|
||||
<member name="permissions/modify_phone_state" type="bool" setter="" getter="">
|
||||
Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls. See [url=https://developer.android.com/reference/android/Manifest.permission#MODIFY_PHONE_STATE]MODIFY_PHONE_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/mount_format_filesystems" type="bool" setter="" getter="">
|
||||
Allows formatting file systems for removable storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MOUNT_FORMAT_FILESYSTEMS]MOUNT_FORMAT_FILESYSTEMS[/url].
|
||||
</member>
|
||||
<member name="permissions/mount_unmount_filesystems" type="bool" setter="" getter="">
|
||||
Allows mounting and unmounting file systems for removable storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MOUNT_UNMOUNT_FILESYSTEMS]MOUNT_UNMOUNT_FILESYSTEMS[/url].
|
||||
</member>
|
||||
<member name="permissions/nfc" type="bool" setter="" getter="">
|
||||
Allows applications to perform I/O operations over NFC. See [url=https://developer.android.com/reference/android/Manifest.permission#NFC]NFC[/url].
|
||||
</member>
|
||||
<member name="permissions/persistent_activity" type="bool" setter="" getter="" deprecated="Deprecated in API level 15.">
|
||||
Allows an application to make its activities persistent.
|
||||
</member>
|
||||
<member name="permissions/post_notifications" type="bool" setter="" getter="">
|
||||
Allows an application to post notifications. Added in API level 33. See [url=https://developer.android.com/develop/ui/views/notifications/notification-permission]Notification runtime permission[/url].
|
||||
</member>
|
||||
<member name="permissions/process_outgoing_calls" type="bool" setter="" getter="" deprecated="Deprecated in API level 29.">
|
||||
Allows an application to see the number being dialed during an outgoing call with the option to redirect the call to a different number or abort the call altogether. See [url=https://developer.android.com/reference/android/Manifest.permission#PROCESS_OUTGOING_CALLS]PROCESS_OUTGOING_CALLS[/url].
|
||||
</member>
|
||||
<member name="permissions/read_calendar" type="bool" setter="" getter="">
|
||||
Allows an application to read the user's calendar data. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_CALENDAR]READ_CALENDAR[/url].
|
||||
</member>
|
||||
<member name="permissions/read_call_log" type="bool" setter="" getter="">
|
||||
Allows an application to read the user's call log. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_CALL_LOG]READ_CALL_LOG[/url].
|
||||
</member>
|
||||
<member name="permissions/read_contacts" type="bool" setter="" getter="">
|
||||
Allows an application to read the user's contacts data. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_CONTACTS]READ_CONTACTS[/url].
|
||||
</member>
|
||||
<member name="permissions/read_external_storage" type="bool" setter="" getter="" deprecated="Deprecated in API level 33.">
|
||||
Allows an application to read from external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE]READ_EXTERNAL_STORAGE[/url].
|
||||
</member>
|
||||
<member name="permissions/read_frame_buffer" type="bool" setter="" getter="">
|
||||
Allows an application to take screen shots and more generally get access to the frame buffer data.
|
||||
</member>
|
||||
<member name="permissions/read_history_bookmarks" type="bool" setter="" getter="">
|
||||
Allows an application to read (but not write) the user's browsing history and bookmarks.
|
||||
</member>
|
||||
<member name="permissions/read_input_state" type="bool" setter="" getter="" deprecated="Deprecated in API level 16.">
|
||||
</member>
|
||||
<member name="permissions/read_logs" type="bool" setter="" getter="">
|
||||
Allows an application to read the low-level system log files. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_LOGS]READ_LOGS[/url].
|
||||
</member>
|
||||
<member name="permissions/read_phone_state" type="bool" setter="" getter="">
|
||||
Allows read only access to phone state. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE]READ_PHONE_STATE[/url].
|
||||
</member>
|
||||
<member name="permissions/read_profile" type="bool" setter="" getter="">
|
||||
Allows an application to read the user's personal profile data.
|
||||
</member>
|
||||
<member name="permissions/read_sms" type="bool" setter="" getter="">
|
||||
Allows an application to read SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SMS]READ_SMS[/url].
|
||||
</member>
|
||||
<member name="permissions/read_social_stream" type="bool" setter="" getter="">
|
||||
Allows an application to read from the user's social stream.
|
||||
</member>
|
||||
<member name="permissions/read_sync_settings" type="bool" setter="" getter="">
|
||||
Allows applications to read the sync settings. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SYNC_SETTINGS]READ_SYNC_SETTINGS[/url].
|
||||
</member>
|
||||
<member name="permissions/read_sync_stats" type="bool" setter="" getter="">
|
||||
Allows applications to read the sync stats. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SYNC_STATS]READ_SYNC_STATS[/url].
|
||||
</member>
|
||||
<member name="permissions/read_user_dictionary" type="bool" setter="" getter="">
|
||||
Allows an application to read the user dictionary.
|
||||
</member>
|
||||
<member name="permissions/reboot" type="bool" setter="" getter="">
|
||||
Required to be able to reboot the device. See [url=https://developer.android.com/reference/android/Manifest.permission#REBOOT]REBOOT[/url].
|
||||
</member>
|
||||
<member name="permissions/receive_boot_completed" type="bool" setter="" getter="">
|
||||
Allows an application to receive the Intent.ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_BOOT_COMPLETED]RECEIVE_BOOT_COMPLETED[/url].
|
||||
</member>
|
||||
<member name="permissions/receive_mms" type="bool" setter="" getter="">
|
||||
Allows an application to monitor incoming MMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_MMS]RECEIVE_MMS[/url].
|
||||
</member>
|
||||
<member name="permissions/receive_sms" type="bool" setter="" getter="">
|
||||
Allows an application to receive SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_SMS]RECEIVE_SMS[/url].
|
||||
</member>
|
||||
<member name="permissions/receive_wap_push" type="bool" setter="" getter="">
|
||||
Allows an application to receive WAP push messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_WAP_PUSH]RECEIVE_WAP_PUSH[/url].
|
||||
</member>
|
||||
<member name="permissions/record_audio" type="bool" setter="" getter="">
|
||||
Allows an application to record audio. See [url=https://developer.android.com/reference/android/Manifest.permission#RECORD_AUDIO]RECORD_AUDIO[/url].
|
||||
</member>
|
||||
<member name="permissions/reorder_tasks" type="bool" setter="" getter="">
|
||||
Allows an application to change the Z-order of tasks. See [url=https://developer.android.com/reference/android/Manifest.permission#REORDER_TASKS]REORDER_TASKS[/url].
|
||||
</member>
|
||||
<member name="permissions/restart_packages" type="bool" setter="" getter="" deprecated="Deprecated in API level 15.">
|
||||
</member>
|
||||
<member name="permissions/send_respond_via_message" type="bool" setter="" getter="">
|
||||
Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls. See [url=https://developer.android.com/reference/android/Manifest.permission#SEND_RESPOND_VIA_MESSAGE]SEND_RESPOND_VIA_MESSAGE[/url].
|
||||
</member>
|
||||
<member name="permissions/send_sms" type="bool" setter="" getter="">
|
||||
Allows an application to send SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#SEND_SMS]SEND_SMS[/url].
|
||||
</member>
|
||||
<member name="permissions/set_activity_watcher" type="bool" setter="" getter="">
|
||||
Allows an application to watch and control how activities are started globally in the system.
|
||||
</member>
|
||||
<member name="permissions/set_alarm" type="bool" setter="" getter="">
|
||||
Allows an application to broadcast an Intent to set an alarm for the user. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_ALARM]SET_ALARM[/url].
|
||||
</member>
|
||||
<member name="permissions/set_always_finish" type="bool" setter="" getter="">
|
||||
Allows an application to control whether activities are immediately finished when put in the background. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_ALWAYS_FINISH]SET_ALWAYS_FINISH[/url].
|
||||
</member>
|
||||
<member name="permissions/set_animation_scale" type="bool" setter="" getter="">
|
||||
Allows to modify the global animation scaling factor. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_ANIMATION_SCALE]SET_ANIMATION_SCALE[/url].
|
||||
</member>
|
||||
<member name="permissions/set_debug_app" type="bool" setter="" getter="">
|
||||
Configure an application for debugging. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_DEBUG_APP]SET_DEBUG_APP[/url].
|
||||
</member>
|
||||
<member name="permissions/set_orientation" type="bool" setter="" getter="">
|
||||
Allows low-level access to setting the orientation (actually rotation) of the screen.
|
||||
</member>
|
||||
<member name="permissions/set_pointer_speed" type="bool" setter="" getter="">
|
||||
Allows low-level access to setting the pointer speed.
|
||||
</member>
|
||||
<member name="permissions/set_preferred_applications" type="bool" setter="" getter="" deprecated="Deprecated in API level 15.">
|
||||
</member>
|
||||
<member name="permissions/set_process_limit" type="bool" setter="" getter="">
|
||||
Allows an application to set the maximum number of (not needed) application processes that can be running. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_PROCESS_LIMIT]SET_PROCESS_LIMIT[/url].
|
||||
</member>
|
||||
<member name="permissions/set_time" type="bool" setter="" getter="">
|
||||
Allows applications to set the system time directly. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_TIME]SET_TIME[/url].
|
||||
</member>
|
||||
<member name="permissions/set_time_zone" type="bool" setter="" getter="">
|
||||
Allows applications to set the system time zone directly. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_TIME_ZONE]SET_TIME_ZONE[/url].
|
||||
</member>
|
||||
<member name="permissions/set_wallpaper" type="bool" setter="" getter="">
|
||||
Allows applications to set the wallpaper. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_WALLPAPER]SET_WALLPAPER[/url].
|
||||
</member>
|
||||
<member name="permissions/set_wallpaper_hints" type="bool" setter="" getter="">
|
||||
Allows applications to set the wallpaper hints. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_WALLPAPER_HINTS]SET_WALLPAPER_HINTS[/url].
|
||||
</member>
|
||||
<member name="permissions/signal_persistent_processes" type="bool" setter="" getter="">
|
||||
Allow an application to request that a signal be sent to all persistent processes. See [url=https://developer.android.com/reference/android/Manifest.permission#SIGNAL_PERSISTENT_PROCESSES]SIGNAL_PERSISTENT_PROCESSES[/url].
|
||||
</member>
|
||||
<member name="permissions/status_bar" type="bool" setter="" getter="">
|
||||
Allows an application to open, close, or disable the status bar and its icons. See [url=https://developer.android.com/reference/android/Manifest.permission#STATUS_BAR]STATUS_BAR[/url].
|
||||
</member>
|
||||
<member name="permissions/subscribed_feeds_read" type="bool" setter="" getter="">
|
||||
Allows an application to allow access the subscribed feeds ContentProvider.
|
||||
</member>
|
||||
<member name="permissions/subscribed_feeds_write" type="bool" setter="" getter="" deprecated="">
|
||||
</member>
|
||||
<member name="permissions/system_alert_window" type="bool" setter="" getter="">
|
||||
Allows an app to create windows using the type WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, shown on top of all other apps. See [url=https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW]SYSTEM_ALERT_WINDOW[/url].
|
||||
</member>
|
||||
<member name="permissions/transmit_ir" type="bool" setter="" getter="">
|
||||
Allows using the device's IR transmitter, if available. See [url=https://developer.android.com/reference/android/Manifest.permission#TRANSMIT_IR]TRANSMIT_IR[/url].
|
||||
</member>
|
||||
<member name="permissions/uninstall_shortcut" type="bool" setter="" getter="" deprecated="">
|
||||
</member>
|
||||
<member name="permissions/update_device_stats" type="bool" setter="" getter="">
|
||||
Allows an application to update device statistics. See [url=https://developer.android.com/reference/android/Manifest.permission#UPDATE_DEVICE_STATS]UPDATE_DEVICE_STATS[/url].
|
||||
</member>
|
||||
<member name="permissions/use_credentials" type="bool" setter="" getter="">
|
||||
Allows an application to request authtokens from the AccountManager.
|
||||
</member>
|
||||
<member name="permissions/use_sip" type="bool" setter="" getter="">
|
||||
Allows an application to use SIP service. See [url=https://developer.android.com/reference/android/Manifest.permission#USE_SIP]USE_SIP[/url].
|
||||
</member>
|
||||
<member name="permissions/vibrate" type="bool" setter="" getter="">
|
||||
Allows access to the vibrator. See [url=https://developer.android.com/reference/android/Manifest.permission#VIBRATE]VIBRATE[/url].
|
||||
</member>
|
||||
<member name="permissions/wake_lock" type="bool" setter="" getter="">
|
||||
Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming. See [url=https://developer.android.com/reference/android/Manifest.permission#WAKE_LOCK]WAKE_LOCK[/url].
|
||||
</member>
|
||||
<member name="permissions/write_apn_settings" type="bool" setter="" getter="">
|
||||
Allows applications to write the apn settings and read sensitive fields of an existing apn settings like user and password. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_APN_SETTINGS]WRITE_APN_SETTINGS[/url].
|
||||
</member>
|
||||
<member name="permissions/write_calendar" type="bool" setter="" getter="">
|
||||
Allows an application to write the user's calendar data. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_CALENDAR]WRITE_CALENDAR[/url].
|
||||
</member>
|
||||
<member name="permissions/write_call_log" type="bool" setter="" getter="">
|
||||
Allows an application to write (but not read) the user's call log data. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_CALL_LOG]WRITE_CALL_LOG[/url].
|
||||
</member>
|
||||
<member name="permissions/write_contacts" type="bool" setter="" getter="">
|
||||
Allows an application to write the user's contacts data. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_CONTACTS]WRITE_CONTACTS[/url].
|
||||
</member>
|
||||
<member name="permissions/write_external_storage" type="bool" setter="" getter="">
|
||||
Allows an application to write to external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE]WRITE_EXTERNAL_STORAGE[/url].
|
||||
</member>
|
||||
<member name="permissions/write_gservices" type="bool" setter="" getter="">
|
||||
Allows an application to modify the Google service map. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_GSERVICES]WRITE_GSERVICES[/url].
|
||||
</member>
|
||||
<member name="permissions/write_history_bookmarks" type="bool" setter="" getter="">
|
||||
Allows an application to write (but not read) the user's browsing history and bookmarks.
|
||||
</member>
|
||||
<member name="permissions/write_profile" type="bool" setter="" getter="">
|
||||
Allows an application to write (but not read) the user's personal profile data.
|
||||
</member>
|
||||
<member name="permissions/write_secure_settings" type="bool" setter="" getter="">
|
||||
Allows an application to read or write the secure system settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SECURE_SETTINGS]WRITE_SECURE_SETTINGS[/url].
|
||||
</member>
|
||||
<member name="permissions/write_settings" type="bool" setter="" getter="">
|
||||
Allows an application to read or write the system settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SETTINGS]WRITE_SETTINGS[/url].
|
||||
</member>
|
||||
<member name="permissions/write_sms" type="bool" setter="" getter="">
|
||||
Allows an application to write SMS messages.
|
||||
</member>
|
||||
<member name="permissions/write_social_stream" type="bool" setter="" getter="">
|
||||
Allows an application to write (but not read) the user's social stream data.
|
||||
</member>
|
||||
<member name="permissions/write_sync_settings" type="bool" setter="" getter="">
|
||||
Allows applications to write the sync settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SYNC_SETTINGS]WRITE_SYNC_SETTINGS[/url].
|
||||
</member>
|
||||
<member name="permissions/write_user_dictionary" type="bool" setter="" getter="">
|
||||
Allows an application to write to the user dictionary.
|
||||
</member>
|
||||
<member name="screen/immersive_mode" type="bool" setter="" getter="">
|
||||
If [code]true[/code], hides navigation and status bar.
|
||||
</member>
|
||||
<member name="screen/support_large" type="bool" setter="" getter="">
|
||||
Indicates whether the application supports larger screen form-factors.
|
||||
</member>
|
||||
<member name="screen/support_normal" type="bool" setter="" getter="">
|
||||
Indicates whether an application supports the "normal" screen form-factors.
|
||||
</member>
|
||||
<member name="screen/support_small" type="bool" setter="" getter="">
|
||||
Indicates whether the application supports smaller screen form-factors.
|
||||
</member>
|
||||
<member name="screen/support_xlarge" type="bool" setter="" getter="">
|
||||
Indicates whether the application supports extra large screen form-factors.
|
||||
</member>
|
||||
<member name="user_data_backup/allow" type="bool" setter="" getter="">
|
||||
If [code]true[/code], allows the application to participate in the backup and restore infrastructure.
|
||||
</member>
|
||||
<member name="version/code" type="int" setter="" getter="">
|
||||
Machine-readable application version. This must be incremented for every new release pushed to the Play Store.
|
||||
</member>
|
||||
<member name="version/name" type="String" setter="" getter="">
|
||||
Application version visible to the user. Falls back to [member ProjectSettings.application/config/version] if left empty.
|
||||
</member>
|
||||
<member name="xr_features/xr_mode" type="int" setter="" getter="">
|
||||
The extended reality (XR) mode for this application.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
67
engine/platform/android/export/export.cpp
Normal file
67
engine/platform/android/export/export.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/**************************************************************************/
|
||||
/* export.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "export.h"
|
||||
|
||||
#include "export_plugin.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "editor/editor_paths.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/export/editor_export.h"
|
||||
|
||||
void register_android_exporter_types() {
|
||||
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformAndroid);
|
||||
}
|
||||
|
||||
void register_android_exporter() {
|
||||
#ifndef ANDROID_ENABLED
|
||||
EDITOR_DEF("export/android/java_sdk_path", OS::get_singleton()->get_environment("JAVA_HOME"));
|
||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/java_sdk_path", PROPERTY_HINT_GLOBAL_DIR));
|
||||
EDITOR_DEF("export/android/android_sdk_path", OS::get_singleton()->get_environment("ANDROID_HOME"));
|
||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/android_sdk_path", PROPERTY_HINT_GLOBAL_DIR));
|
||||
EDITOR_DEF("export/android/debug_keystore", EditorPaths::get_singleton()->get_debug_keystore_path());
|
||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"));
|
||||
EDITOR_DEF("export/android/debug_keystore_user", DEFAULT_ANDROID_KEYSTORE_DEBUG_USER);
|
||||
EDITOR_DEF("export/android/debug_keystore_pass", DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD);
|
||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore_pass", PROPERTY_HINT_PASSWORD));
|
||||
EDITOR_DEF("export/android/force_system_user", false);
|
||||
|
||||
EDITOR_DEF("export/android/shutdown_adb_on_exit", true);
|
||||
|
||||
EDITOR_DEF("export/android/one_click_deploy_clear_previous_install", false);
|
||||
|
||||
EDITOR_DEF("export/android/use_wifi_for_remote_debug", false);
|
||||
EDITOR_DEF("export/android/wifi_remote_debug_host", "localhost");
|
||||
#endif
|
||||
|
||||
Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>(memnew(EditorExportPlatformAndroid));
|
||||
EditorExport::get_singleton()->add_export_platform(exporter);
|
||||
}
|
||||
37
engine/platform/android/export/export.h
Normal file
37
engine/platform/android/export/export.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/**************************************************************************/
|
||||
/* export.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_EXPORT_H
|
||||
#define ANDROID_EXPORT_H
|
||||
|
||||
void register_android_exporter_types();
|
||||
void register_android_exporter();
|
||||
|
||||
#endif // ANDROID_EXPORT_H
|
||||
3644
engine/platform/android/export/export_plugin.cpp
Normal file
3644
engine/platform/android/export/export_plugin.cpp
Normal file
File diff suppressed because it is too large
Load diff
269
engine/platform/android/export/export_plugin.h
Normal file
269
engine/platform/android/export/export_plugin.h
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/**************************************************************************/
|
||||
/* export_plugin.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_EXPORT_PLUGIN_H
|
||||
#define ANDROID_EXPORT_PLUGIN_H
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
#include "godot_plugin_config.h"
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
#include "core/io/zip_io.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/export/editor_export_platform.h"
|
||||
|
||||
// Optional environment variables for defining confidential information. If any
|
||||
// of these is set, they will override the values set in the credentials file.
|
||||
const String ENV_ANDROID_KEYSTORE_DEBUG_PATH = "GODOT_ANDROID_KEYSTORE_DEBUG_PATH";
|
||||
const String ENV_ANDROID_KEYSTORE_DEBUG_USER = "GODOT_ANDROID_KEYSTORE_DEBUG_USER";
|
||||
const String ENV_ANDROID_KEYSTORE_DEBUG_PASS = "GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD";
|
||||
const String ENV_ANDROID_KEYSTORE_RELEASE_PATH = "GODOT_ANDROID_KEYSTORE_RELEASE_PATH";
|
||||
const String ENV_ANDROID_KEYSTORE_RELEASE_USER = "GODOT_ANDROID_KEYSTORE_RELEASE_USER";
|
||||
const String ENV_ANDROID_KEYSTORE_RELEASE_PASS = "GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD";
|
||||
|
||||
const String DEFAULT_ANDROID_KEYSTORE_DEBUG_USER = "androiddebugkey";
|
||||
const String DEFAULT_ANDROID_KEYSTORE_DEBUG_PASSWORD = "android";
|
||||
|
||||
struct LauncherIcon {
|
||||
const char *export_path;
|
||||
int dimensions = 0;
|
||||
};
|
||||
|
||||
class EditorExportPlatformAndroid : public EditorExportPlatform {
|
||||
GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform);
|
||||
|
||||
Ref<ImageTexture> logo;
|
||||
Ref<ImageTexture> run_icon;
|
||||
|
||||
struct Device {
|
||||
String id;
|
||||
String name;
|
||||
String description;
|
||||
int api_level = 0;
|
||||
String architecture;
|
||||
};
|
||||
|
||||
struct APKExportData {
|
||||
zipFile apk;
|
||||
EditorProgress *ep = nullptr;
|
||||
};
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
mutable Vector<PluginConfigAndroid> android_plugins;
|
||||
mutable SafeFlag android_plugins_changed;
|
||||
Mutex android_plugins_lock;
|
||||
#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;
|
||||
Mutex device_lock;
|
||||
#ifndef ANDROID_ENABLED
|
||||
Thread check_for_changes_thread;
|
||||
SafeFlag quit_request;
|
||||
SafeFlag has_runnable_preset;
|
||||
|
||||
static void _check_for_changes_poll_thread(void *ud);
|
||||
void _update_preset_status();
|
||||
#endif
|
||||
|
||||
String get_project_name(const String &p_name) const;
|
||||
|
||||
String get_package_name(const String &p_package) const;
|
||||
|
||||
String get_valid_basename() const;
|
||||
|
||||
String get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const;
|
||||
|
||||
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
|
||||
bool is_project_name_valid() const;
|
||||
|
||||
static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data);
|
||||
|
||||
static zip_fileinfo get_zip_fileinfo();
|
||||
|
||||
struct ABI {
|
||||
String abi;
|
||||
String arch;
|
||||
|
||||
bool operator==(const ABI &p_a) const {
|
||||
return p_a.abi == abi;
|
||||
}
|
||||
|
||||
ABI(const String &p_abi, const String &p_arch) {
|
||||
abi = p_abi;
|
||||
arch = p_arch;
|
||||
}
|
||||
ABI() {}
|
||||
};
|
||||
|
||||
static Vector<ABI> get_abis();
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
/// List the gdap files in the directory specified by the p_path parameter.
|
||||
static Vector<String> list_gdap_files(const String &p_path);
|
||||
|
||||
static Vector<PluginConfigAndroid> get_plugins();
|
||||
|
||||
static Vector<PluginConfigAndroid> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets);
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED);
|
||||
|
||||
static Error save_apk_so(void *p_userdata, const SharedObject &p_so);
|
||||
|
||||
static Error save_apk_file(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);
|
||||
|
||||
static Error ignore_apk_file(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);
|
||||
|
||||
static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so);
|
||||
|
||||
bool _has_read_write_storage_permission(const Vector<String> &p_permissions);
|
||||
|
||||
bool _has_manage_external_storage_permission(const Vector<String> &p_permissions);
|
||||
|
||||
void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions);
|
||||
|
||||
void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug);
|
||||
|
||||
void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet);
|
||||
|
||||
static String _get_keystore_path(const Ref<EditorExportPreset> &p_preset, bool p_debug);
|
||||
|
||||
static String _parse_string(const uint8_t *p_bytes, bool p_utf8);
|
||||
|
||||
void _fix_resources(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &r_manifest);
|
||||
|
||||
void _load_image_data(const Ref<Image> &p_splash_image, Vector<uint8_t> &p_data);
|
||||
|
||||
void _process_launcher_icons(const String &p_file_name, const Ref<Image> &p_source_image, int dimension, Vector<uint8_t> &p_data);
|
||||
|
||||
void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background);
|
||||
|
||||
void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
|
||||
const Ref<Image> &p_main_image,
|
||||
const Ref<Image> &p_foreground,
|
||||
const Ref<Image> &p_background);
|
||||
|
||||
static void _create_editor_debug_keystore_if_needed();
|
||||
|
||||
static Vector<ABI> get_enabled_abis(const Ref<EditorExportPreset> &p_preset);
|
||||
|
||||
static bool _uses_vulkan();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
typedef Error (*EditorExportSaveFunction)(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);
|
||||
|
||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
||||
|
||||
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;
|
||||
|
||||
virtual String get_os_name() const override;
|
||||
|
||||
virtual Ref<Texture2D> get_logo() const override;
|
||||
|
||||
virtual bool should_update_export_options() override;
|
||||
|
||||
virtual bool poll_export() override;
|
||||
|
||||
virtual int get_options_count() const override;
|
||||
|
||||
virtual String get_options_tooltip() const override;
|
||||
|
||||
virtual String get_option_label(int p_index) const override;
|
||||
|
||||
virtual String get_option_tooltip(int p_index) const override;
|
||||
|
||||
virtual String get_device_architecture(int p_index) const override;
|
||||
|
||||
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
|
||||
|
||||
virtual Ref<Texture2D> get_run_icon() const override;
|
||||
|
||||
static String get_adb_path();
|
||||
|
||||
static String get_apksigner_path(int p_target_sdk = -1, bool p_check_executes = false);
|
||||
|
||||
static String get_java_path();
|
||||
|
||||
static String get_keytool_path();
|
||||
|
||||
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
|
||||
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
|
||||
static bool has_valid_username_and_password(const Ref<EditorExportPreset> &p_preset, String &r_error);
|
||||
|
||||
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
|
||||
|
||||
String _get_plugins_names(const Ref<EditorExportPreset> &p_preset) const;
|
||||
|
||||
String _resolve_export_plugin_android_library_path(const String &p_android_library_path) const;
|
||||
|
||||
bool _is_clean_build_required(const Ref<EditorExportPreset> &p_preset);
|
||||
|
||||
String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
||||
|
||||
Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
|
||||
|
||||
void get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags);
|
||||
|
||||
Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep);
|
||||
|
||||
void _clear_assets_directory(const Ref<EditorExportPreset> &p_preset);
|
||||
|
||||
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);
|
||||
|
||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
|
||||
|
||||
Error export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags);
|
||||
|
||||
virtual void get_platform_features(List<String> *r_features) const override;
|
||||
|
||||
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override;
|
||||
|
||||
EditorExportPlatformAndroid();
|
||||
|
||||
~EditorExportPlatformAndroid();
|
||||
};
|
||||
|
||||
#endif // ANDROID_EXPORT_PLUGIN_H
|
||||
199
engine/platform/android/export/godot_plugin_config.cpp
Normal file
199
engine/platform/android/export/godot_plugin_config.cpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/**************************************************************************/
|
||||
/* godot_plugin_config.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "godot_plugin_config.h"
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
/*
|
||||
* Set of prebuilt plugins.
|
||||
* Currently unused, this is just for future reference:
|
||||
*/
|
||||
// static const PluginConfigAndroid MY_PREBUILT_PLUGIN = {
|
||||
// /*.valid_config =*/true,
|
||||
// /*.last_updated =*/0,
|
||||
// /*.name =*/"GodotPayment",
|
||||
// /*.binary_type =*/"local",
|
||||
// /*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar",
|
||||
// /*.local_dependencies =*/{},
|
||||
// /*.remote_dependencies =*/String("com.android.billingclient:billing:2.2.1").split("|"),
|
||||
// /*.custom_maven_repos =*/{}
|
||||
// };
|
||||
|
||||
String PluginConfigAndroid::resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
|
||||
String absolute_path;
|
||||
if (!dependency_path.is_empty()) {
|
||||
if (dependency_path.is_absolute_path()) {
|
||||
absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path);
|
||||
} else {
|
||||
absolute_path = plugin_config_dir.path_join(dependency_path);
|
||||
}
|
||||
}
|
||||
|
||||
return absolute_path;
|
||||
}
|
||||
|
||||
PluginConfigAndroid PluginConfigAndroid::resolve_prebuilt_plugin(PluginConfigAndroid prebuilt_plugin, String plugin_config_dir) {
|
||||
PluginConfigAndroid resolved = prebuilt_plugin;
|
||||
resolved.binary = resolved.binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL ? resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.binary) : prebuilt_plugin.binary;
|
||||
if (!prebuilt_plugin.local_dependencies.is_empty()) {
|
||||
resolved.local_dependencies.clear();
|
||||
for (int i = 0; i < prebuilt_plugin.local_dependencies.size(); i++) {
|
||||
resolved.local_dependencies.push_back(resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.local_dependencies[i]));
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
Vector<PluginConfigAndroid> PluginConfigAndroid::get_prebuilt_plugins(String plugins_base_dir) {
|
||||
Vector<PluginConfigAndroid> prebuilt_plugins;
|
||||
return prebuilt_plugins;
|
||||
}
|
||||
|
||||
bool PluginConfigAndroid::is_plugin_config_valid(PluginConfigAndroid plugin_config) {
|
||||
bool valid_name = !plugin_config.name.is_empty();
|
||||
bool valid_binary_type = plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL ||
|
||||
plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE;
|
||||
|
||||
bool valid_binary = false;
|
||||
if (valid_binary_type) {
|
||||
valid_binary = !plugin_config.binary.is_empty() &&
|
||||
(plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE ||
|
||||
FileAccess::exists(plugin_config.binary));
|
||||
}
|
||||
|
||||
bool valid_local_dependencies = true;
|
||||
if (!plugin_config.local_dependencies.is_empty()) {
|
||||
for (int i = 0; i < plugin_config.local_dependencies.size(); i++) {
|
||||
if (!FileAccess::exists(plugin_config.local_dependencies[i])) {
|
||||
valid_local_dependencies = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid_name && valid_binary && valid_binary_type && valid_local_dependencies;
|
||||
}
|
||||
|
||||
uint64_t PluginConfigAndroid::get_plugin_modification_time(const PluginConfigAndroid &plugin_config, const String &config_path) {
|
||||
uint64_t last_updated = FileAccess::get_modified_time(config_path);
|
||||
last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary));
|
||||
|
||||
for (int i = 0; i < plugin_config.local_dependencies.size(); i++) {
|
||||
String binary = plugin_config.local_dependencies.get(i);
|
||||
last_updated = MAX(last_updated, FileAccess::get_modified_time(binary));
|
||||
}
|
||||
|
||||
return last_updated;
|
||||
}
|
||||
|
||||
PluginConfigAndroid PluginConfigAndroid::load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
|
||||
PluginConfigAndroid plugin_config = {};
|
||||
|
||||
if (config_file.is_valid()) {
|
||||
Error err = config_file->load(path);
|
||||
if (err == OK) {
|
||||
String config_base_dir = path.get_base_dir();
|
||||
|
||||
plugin_config.name = config_file->get_value(PluginConfigAndroid::CONFIG_SECTION, PluginConfigAndroid::CONFIG_NAME_KEY, String());
|
||||
plugin_config.binary_type = config_file->get_value(PluginConfigAndroid::CONFIG_SECTION, PluginConfigAndroid::CONFIG_BINARY_TYPE_KEY, String());
|
||||
|
||||
String binary_path = config_file->get_value(PluginConfigAndroid::CONFIG_SECTION, PluginConfigAndroid::CONFIG_BINARY_KEY, String());
|
||||
plugin_config.binary = plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL ? resolve_local_dependency_path(config_base_dir, binary_path) : binary_path;
|
||||
|
||||
if (config_file->has_section(PluginConfigAndroid::DEPENDENCIES_SECTION)) {
|
||||
Vector<String> local_dependencies_paths = config_file->get_value(PluginConfigAndroid::DEPENDENCIES_SECTION, PluginConfigAndroid::DEPENDENCIES_LOCAL_KEY, Vector<String>());
|
||||
if (!local_dependencies_paths.is_empty()) {
|
||||
for (int i = 0; i < local_dependencies_paths.size(); i++) {
|
||||
plugin_config.local_dependencies.push_back(resolve_local_dependency_path(config_base_dir, local_dependencies_paths[i]));
|
||||
}
|
||||
}
|
||||
|
||||
plugin_config.remote_dependencies = config_file->get_value(PluginConfigAndroid::DEPENDENCIES_SECTION, PluginConfigAndroid::DEPENDENCIES_REMOTE_KEY, Vector<String>());
|
||||
plugin_config.custom_maven_repos = config_file->get_value(PluginConfigAndroid::DEPENDENCIES_SECTION, PluginConfigAndroid::DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY, Vector<String>());
|
||||
}
|
||||
|
||||
plugin_config.valid_config = is_plugin_config_valid(plugin_config);
|
||||
plugin_config.last_updated = get_plugin_modification_time(plugin_config, path);
|
||||
}
|
||||
}
|
||||
|
||||
return plugin_config;
|
||||
}
|
||||
|
||||
void PluginConfigAndroid::get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result) {
|
||||
if (!plugins_configs.is_empty()) {
|
||||
for (int i = 0; i < plugins_configs.size(); i++) {
|
||||
PluginConfigAndroid config = plugins_configs[i];
|
||||
if (!config.valid_config) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.binary_type == binary_type) {
|
||||
r_result.push_back(config.binary);
|
||||
}
|
||||
|
||||
if (binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL) {
|
||||
r_result.append_array(config.local_dependencies);
|
||||
}
|
||||
|
||||
if (binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE) {
|
||||
r_result.append_array(config.remote_dependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PluginConfigAndroid::get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result) {
|
||||
if (!plugins_configs.is_empty()) {
|
||||
for (int i = 0; i < plugins_configs.size(); i++) {
|
||||
PluginConfigAndroid config = plugins_configs[i];
|
||||
if (!config.valid_config) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r_result.append_array(config.custom_maven_repos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PluginConfigAndroid::get_plugins_names(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result) {
|
||||
if (!plugins_configs.is_empty()) {
|
||||
for (int i = 0; i < plugins_configs.size(); i++) {
|
||||
PluginConfigAndroid config = plugins_configs[i];
|
||||
if (!config.valid_config) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r_result.push_back(config.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
108
engine/platform/android/export/godot_plugin_config.h
Normal file
108
engine/platform/android/export/godot_plugin_config.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**************************************************************************/
|
||||
/* godot_plugin_config.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_GODOT_PLUGIN_CONFIG_H
|
||||
#define ANDROID_GODOT_PLUGIN_CONFIG_H
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/error/error_list.h"
|
||||
#include "core/io/config_file.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
/*
|
||||
The `config` section and fields are required and defined as follow:
|
||||
- **name**: name of the plugin.
|
||||
- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field.
|
||||
- **binary**:
|
||||
- if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`).
|
||||
- if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0").
|
||||
|
||||
The `dependencies` section and fields are optional and defined as follow:
|
||||
- **local**: contains a list of local `.aar` binary files the plugin depends on. The local binary dependencies must also be located in the `res://android/plugins` directory.
|
||||
- **remote**: contains a list of remote binary gradle dependencies for the plugin.
|
||||
- **custom_maven_repos**: contains a list of urls specifying custom maven repos required for the plugin's dependencies.
|
||||
|
||||
See https://github.com/godotengine/godot/issues/38157#issuecomment-618773871
|
||||
*/
|
||||
struct PluginConfigAndroid {
|
||||
inline static const char *PLUGIN_CONFIG_EXT = ".gdap";
|
||||
|
||||
inline static const char *CONFIG_SECTION = "config";
|
||||
inline static const char *CONFIG_NAME_KEY = "name";
|
||||
inline static const char *CONFIG_BINARY_TYPE_KEY = "binary_type";
|
||||
inline static const char *CONFIG_BINARY_KEY = "binary";
|
||||
|
||||
inline static const char *DEPENDENCIES_SECTION = "dependencies";
|
||||
inline static const char *DEPENDENCIES_LOCAL_KEY = "local";
|
||||
inline static const char *DEPENDENCIES_REMOTE_KEY = "remote";
|
||||
inline static const char *DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY = "custom_maven_repos";
|
||||
|
||||
inline static const char *BINARY_TYPE_LOCAL = "local";
|
||||
inline static const char *BINARY_TYPE_REMOTE = "remote";
|
||||
|
||||
// Set to true when the config file is properly loaded.
|
||||
bool valid_config = false;
|
||||
// Unix timestamp of last change to this plugin.
|
||||
uint64_t last_updated = 0;
|
||||
|
||||
// Required config section
|
||||
String name;
|
||||
String binary_type;
|
||||
String binary;
|
||||
|
||||
// Optional dependencies section
|
||||
Vector<String> local_dependencies;
|
||||
Vector<String> remote_dependencies;
|
||||
Vector<String> custom_maven_repos;
|
||||
|
||||
static String resolve_local_dependency_path(String plugin_config_dir, String dependency_path);
|
||||
|
||||
static PluginConfigAndroid resolve_prebuilt_plugin(PluginConfigAndroid prebuilt_plugin, String plugin_config_dir);
|
||||
|
||||
static Vector<PluginConfigAndroid> get_prebuilt_plugins(String plugins_base_dir);
|
||||
|
||||
static bool is_plugin_config_valid(PluginConfigAndroid plugin_config);
|
||||
|
||||
static uint64_t get_plugin_modification_time(const PluginConfigAndroid &plugin_config, const String &config_path);
|
||||
|
||||
static PluginConfigAndroid load_plugin_config(Ref<ConfigFile> config_file, const String &path);
|
||||
|
||||
static void get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result);
|
||||
|
||||
static void get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result);
|
||||
|
||||
static void get_plugins_names(Vector<PluginConfigAndroid> plugins_configs, Vector<String> &r_result);
|
||||
};
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
||||
#endif // ANDROID_GODOT_PLUGIN_CONFIG_H
|
||||
340
engine/platform/android/export/gradle_export_util.cpp
Normal file
340
engine/platform/android/export/gradle_export_util.cpp
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/**************************************************************************/
|
||||
/* gradle_export_util.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "gradle_export_util.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
|
||||
switch (screen_orientation) {
|
||||
case DisplayServer::SCREEN_PORTRAIT:
|
||||
return 1;
|
||||
case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
|
||||
return 8;
|
||||
case DisplayServer::SCREEN_REVERSE_PORTRAIT:
|
||||
return 9;
|
||||
case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
|
||||
return 11;
|
||||
case DisplayServer::SCREEN_SENSOR_PORTRAIT:
|
||||
return 12;
|
||||
case DisplayServer::SCREEN_SENSOR:
|
||||
return 13;
|
||||
case DisplayServer::SCREEN_LANDSCAPE:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation) {
|
||||
switch (screen_orientation) {
|
||||
case DisplayServer::SCREEN_PORTRAIT:
|
||||
return "portrait";
|
||||
case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
|
||||
return "reverseLandscape";
|
||||
case DisplayServer::SCREEN_REVERSE_PORTRAIT:
|
||||
return "reversePortrait";
|
||||
case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
|
||||
return "userLandscape";
|
||||
case DisplayServer::SCREEN_SENSOR_PORTRAIT:
|
||||
return "userPortrait";
|
||||
case DisplayServer::SCREEN_SENSOR:
|
||||
return "fullUser";
|
||||
case DisplayServer::SCREEN_LANDSCAPE:
|
||||
default:
|
||||
return "landscape";
|
||||
}
|
||||
}
|
||||
|
||||
int _get_app_category_value(int category_index) {
|
||||
switch (category_index) {
|
||||
case APP_CATEGORY_ACCESSIBILITY:
|
||||
return 8;
|
||||
case APP_CATEGORY_AUDIO:
|
||||
return 1;
|
||||
case APP_CATEGORY_IMAGE:
|
||||
return 3;
|
||||
case APP_CATEGORY_MAPS:
|
||||
return 6;
|
||||
case APP_CATEGORY_NEWS:
|
||||
return 5;
|
||||
case APP_CATEGORY_PRODUCTIVITY:
|
||||
return 7;
|
||||
case APP_CATEGORY_SOCIAL:
|
||||
return 4;
|
||||
case APP_CATEGORY_VIDEO:
|
||||
return 2;
|
||||
case APP_CATEGORY_GAME:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
String _get_app_category_label(int category_index) {
|
||||
switch (category_index) {
|
||||
case APP_CATEGORY_ACCESSIBILITY:
|
||||
return "accessibility";
|
||||
case APP_CATEGORY_AUDIO:
|
||||
return "audio";
|
||||
case APP_CATEGORY_IMAGE:
|
||||
return "image";
|
||||
case APP_CATEGORY_MAPS:
|
||||
return "maps";
|
||||
case APP_CATEGORY_NEWS:
|
||||
return "news";
|
||||
case APP_CATEGORY_PRODUCTIVITY:
|
||||
return "productivity";
|
||||
case APP_CATEGORY_SOCIAL:
|
||||
return "social";
|
||||
case APP_CATEGORY_VIDEO:
|
||||
return "video";
|
||||
case APP_CATEGORY_GAME:
|
||||
default:
|
||||
return "game";
|
||||
}
|
||||
}
|
||||
|
||||
// Utility method used to create a directory.
|
||||
Error create_directory(const String &p_dir) {
|
||||
if (!DirAccess::exists(p_dir)) {
|
||||
Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'.");
|
||||
Error err = filesystem_da->make_dir_recursive(p_dir);
|
||||
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'.");
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Writes p_data into a file at p_path, creating directories if necessary.
|
||||
// Note: this will overwrite the file at p_path if it already exists.
|
||||
Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) {
|
||||
String dir = p_path.get_base_dir();
|
||||
Error err = create_directory(dir);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
|
||||
fa->store_buffer(p_data.ptr(), p_data.size());
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Writes string p_data into a file at p_path, creating directories if necessary.
|
||||
// Note: this will overwrite the file at p_path if it already exists.
|
||||
Error store_string_at_path(const String &p_path, const String &p_data) {
|
||||
String dir = p_path.get_base_dir();
|
||||
Error err = create_directory(dir);
|
||||
if (err != OK) {
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
print_error("Unable to write data into " + p_path);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
|
||||
fa->store_string(p_data);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Implementation of EditorExportSaveFunction.
|
||||
// This method will only be called as an input to export_project_files.
|
||||
// It is used by the export_project_files method to save all the asset files into the gradle project.
|
||||
// It's functionality mirrors that of the method save_apk_file.
|
||||
// This method will be called ONLY when gradle build is enabled.
|
||||
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) {
|
||||
CustomExportData *export_data = static_cast<CustomExportData *>(p_userdata);
|
||||
String dst_path = p_path.replace_first("res://", export_data->assets_directory + "/");
|
||||
print_verbose("Saving project files from " + p_path + " into " + dst_path);
|
||||
Error err = store_file_at_path(dst_path, p_data);
|
||||
return err;
|
||||
}
|
||||
|
||||
String _android_xml_escape(const String &p_string) {
|
||||
// Android XML requires strings to be both valid XML (`xml_escape()`) but also
|
||||
// to escape characters which are valid XML but have special meaning in Android XML.
|
||||
// https://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
|
||||
// Note: Didn't handle U+XXXX unicode chars, could be done if needed.
|
||||
return p_string
|
||||
.replace("@", "\\@")
|
||||
.replace("?", "\\?")
|
||||
.replace("'", "\\'")
|
||||
.replace("\"", "\\\"")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\t", "\\t")
|
||||
.xml_escape(false);
|
||||
}
|
||||
|
||||
// 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, 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(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(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.");
|
||||
}
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
da->list_dir_begin();
|
||||
Dictionary appnames = GLOBAL_GET("application/config/name_localized");
|
||||
while (true) {
|
||||
String file = da->get_next();
|
||||
if (file.is_empty()) {
|
||||
break;
|
||||
}
|
||||
if (!file.begins_with("values-")) {
|
||||
// NOTE: This assumes all directories that start with "values-" are for localization.
|
||||
continue;
|
||||
}
|
||||
String locale = file.replace("values-", "").replace("-r", "_");
|
||||
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));
|
||||
print_verbose("Storing project name for locale " + locale + " under " + locale_directory);
|
||||
store_string_at_path(locale_directory, processed_xml_string);
|
||||
} else {
|
||||
// TODO: Once the legacy build system is deprecated we don't need to have xml files for this else branch
|
||||
store_string_at_path(locale_directory, processed_default_xml_string);
|
||||
}
|
||||
}
|
||||
da->list_dir_end();
|
||||
return OK;
|
||||
}
|
||||
|
||||
String bool_to_string(bool v) {
|
||||
return v ? "true" : "false";
|
||||
}
|
||||
|
||||
String _get_gles_tag() {
|
||||
return " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n";
|
||||
}
|
||||
|
||||
String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
|
||||
String manifest_screen_sizes = " <supports-screens \n tools:node=\"replace\"";
|
||||
String sizes[] = { "small", "normal", "large", "xlarge" };
|
||||
size_t num_sizes = sizeof(sizes) / sizeof(sizes[0]);
|
||||
for (size_t i = 0; i < num_sizes; i++) {
|
||||
String feature_name = vformat("screen/support_%s", sizes[i]);
|
||||
String feature_support = bool_to_string(p_preset->get(feature_name));
|
||||
String xml_entry = vformat("\n android:%sScreens=\"%s\"", sizes[i], feature_support);
|
||||
manifest_screen_sizes += xml_entry;
|
||||
}
|
||||
manifest_screen_sizes += " />\n";
|
||||
return manifest_screen_sizes;
|
||||
}
|
||||
|
||||
String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug) {
|
||||
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
|
||||
String manifest_activity_text = vformat(
|
||||
" <activity android:name=\"com.godot.game.GodotApp\" "
|
||||
"tools:replace=\"android:screenOrientation,android:excludeFromRecents,android:resizeableActivity\" "
|
||||
"tools:node=\"mergeOnlyAttributes\" "
|
||||
"android:excludeFromRecents=\"%s\" "
|
||||
"android:screenOrientation=\"%s\" "
|
||||
"android:resizeableActivity=\"%s\">\n",
|
||||
bool_to_string(p_preset->get("package/exclude_from_recents")),
|
||||
orientation,
|
||||
bool_to_string(bool(GLOBAL_GET("display/window/size/resizable"))));
|
||||
|
||||
manifest_activity_text += " <intent-filter>\n"
|
||||
" <action android:name=\"android.intent.action.MAIN\" />\n"
|
||||
" <category android:name=\"android.intent.category.DEFAULT\" />\n";
|
||||
|
||||
bool show_in_app_library = p_preset->get("package/show_in_app_library");
|
||||
if (show_in_app_library) {
|
||||
manifest_activity_text += " <category android:name=\"android.intent.category.LAUNCHER\" />\n";
|
||||
}
|
||||
|
||||
bool uses_leanback_category = p_preset->get("package/show_in_android_tv");
|
||||
if (uses_leanback_category) {
|
||||
manifest_activity_text += " <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n";
|
||||
}
|
||||
|
||||
bool uses_home_category = p_preset->get("package/show_as_launcher_app");
|
||||
if (uses_home_category) {
|
||||
manifest_activity_text += " <category android:name=\"android.intent.category.HOME\" />\n";
|
||||
}
|
||||
|
||||
manifest_activity_text += " </intent-filter>\n";
|
||||
|
||||
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
|
||||
for (int i = 0; i < export_plugins.size(); i++) {
|
||||
if (export_plugins[i]->supports_platform(p_export_platform)) {
|
||||
const String contents = export_plugins[i]->get_android_manifest_activity_element_contents(p_export_platform, p_debug);
|
||||
if (!contents.is_empty()) {
|
||||
manifest_activity_text += contents;
|
||||
manifest_activity_text += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manifest_activity_text += " </activity>\n";
|
||||
return manifest_activity_text;
|
||||
}
|
||||
|
||||
String _get_application_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission, bool p_debug) {
|
||||
int app_category_index = (int)(p_preset->get("package/app_category"));
|
||||
bool is_game = app_category_index == APP_CATEGORY_GAME;
|
||||
|
||||
String manifest_application_text = vformat(
|
||||
" <application android:label=\"@string/godot_project_name_string\"\n"
|
||||
" android:allowBackup=\"%s\"\n"
|
||||
" android:icon=\"@mipmap/icon\"\n"
|
||||
" android:appCategory=\"%s\"\n"
|
||||
" android:isGame=\"%s\"\n"
|
||||
" android:hasFragileUserData=\"%s\"\n"
|
||||
" android:requestLegacyExternalStorage=\"%s\"\n"
|
||||
" tools:replace=\"android:allowBackup,android:appCategory,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n"
|
||||
" tools:ignore=\"GoogleAppIndexingWarning\">\n\n",
|
||||
bool_to_string(p_preset->get("user_data_backup/allow")),
|
||||
_get_app_category_label(app_category_index),
|
||||
bool_to_string(is_game),
|
||||
bool_to_string(p_preset->get("package/retain_data_on_uninstall")),
|
||||
bool_to_string(p_has_read_write_storage_permission));
|
||||
|
||||
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
|
||||
for (int i = 0; i < export_plugins.size(); i++) {
|
||||
if (export_plugins[i]->supports_platform(p_export_platform)) {
|
||||
const String contents = export_plugins[i]->get_android_manifest_application_element_contents(p_export_platform, p_debug);
|
||||
if (!contents.is_empty()) {
|
||||
manifest_application_text += contents;
|
||||
manifest_application_text += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manifest_application_text += _get_activity_tag(p_export_platform, p_preset, p_debug);
|
||||
manifest_application_text += " </application>\n";
|
||||
return manifest_application_text;
|
||||
}
|
||||
110
engine/platform/android/export/gradle_export_util.h
Normal file
110
engine/platform/android/export/gradle_export_util.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/**************************************************************************/
|
||||
/* gradle_export_util.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ANDROID_GRADLE_EXPORT_UTIL_H
|
||||
#define ANDROID_GRADLE_EXPORT_UTIL_H
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/zip_io.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/export/editor_export.h"
|
||||
|
||||
const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">%s</string>
|
||||
</resources>
|
||||
)";
|
||||
|
||||
// Application category.
|
||||
// See https://developer.android.com/guide/topics/manifest/application-element#appCategory for standards
|
||||
static const int APP_CATEGORY_ACCESSIBILITY = 0;
|
||||
static const int APP_CATEGORY_AUDIO = 1;
|
||||
static const int APP_CATEGORY_GAME = 2;
|
||||
static const int APP_CATEGORY_IMAGE = 3;
|
||||
static const int APP_CATEGORY_MAPS = 4;
|
||||
static const int APP_CATEGORY_NEWS = 5;
|
||||
static const int APP_CATEGORY_PRODUCTIVITY = 6;
|
||||
static const int APP_CATEGORY_SOCIAL = 7;
|
||||
static const int APP_CATEGORY_VIDEO = 8;
|
||||
|
||||
// Supported XR modes.
|
||||
// This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java'
|
||||
static const int XR_MODE_REGULAR = 0;
|
||||
static const int XR_MODE_OPENXR = 1;
|
||||
|
||||
struct CustomExportData {
|
||||
String assets_directory;
|
||||
String libs_directory;
|
||||
bool debug;
|
||||
Vector<String> libs;
|
||||
};
|
||||
|
||||
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation);
|
||||
|
||||
String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation);
|
||||
|
||||
int _get_app_category_value(int category_index);
|
||||
|
||||
String _get_app_category_label(int category_index);
|
||||
|
||||
// Utility method used to create a directory.
|
||||
Error create_directory(const String &p_dir);
|
||||
|
||||
// Writes p_data into a file at p_path, creating directories if necessary.
|
||||
// Note: this will overwrite the file at p_path if it already exists.
|
||||
Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data);
|
||||
|
||||
// Writes string p_data into a file at p_path, creating directories if necessary.
|
||||
// Note: this will overwrite the file at p_path if it already exists.
|
||||
Error store_string_at_path(const String &p_path, const String &p_data);
|
||||
|
||||
// Implementation of EditorExportSaveFunction.
|
||||
// This method will only be called as an input to export_project_files.
|
||||
// It is used by the export_project_files method to save all the asset files into the gradle project.
|
||||
// It's functionality mirrors that of the method save_apk_file.
|
||||
// This method will be called ONLY when gradle build is enabled.
|
||||
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, const String &p_gradle_build_dir);
|
||||
|
||||
String bool_to_string(bool v);
|
||||
|
||||
String _get_gles_tag();
|
||||
|
||||
String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset);
|
||||
|
||||
String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug);
|
||||
|
||||
String _get_application_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission, bool p_debug);
|
||||
|
||||
#endif // ANDROID_GRADLE_EXPORT_UTIL_H
|
||||
1
engine/platform/android/export/logo.svg
Normal file
1
engine/platform/android/export/logo.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path fill="#56d881" d="M22.904 20.192a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25m-13.808 0a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25m14.256-7.525 2.496-4.323a.52.52 0 1 0-.899-.52l-2.528 4.378a15.69 15.69 0 0 0-12.842 0L7.051 7.823a.52.52 0 1 0-.9.521l2.497 4.323C4.361 15 1.43 19.34 1 24.467h30c-.43-5.128-3.361-9.468-7.648-11.8"/></svg>
|
||||
|
After Width: | Height: | Size: 421 B |
1
engine/platform/android/export/run_icon.svg
Normal file
1
engine/platform/android/export/run_icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path fill="#e0e0e0" d="M11.187 9.936a.577.577 0 1 1 .578-.578.577.577 0 0 1-.578.578m-6.374 0a.577.577 0 1 1 .577-.578.577.577 0 0 1-.577.578m6.581-3.475 1.153-1.996a.24.24 0 1 0-.415-.24l-1.167 2.021a7.244 7.244 0 0 0-5.93 0L3.868 4.225a.24.24 0 1 0-.415.24l1.153 1.996a6.806 6.806 0 0 0-3.532 5.448h13.852a6.807 6.807 0 0 0-3.532-5.448"/></svg>
|
||||
|
After Width: | Height: | Size: 431 B |
276
engine/platform/android/file_access_android.cpp
Normal file
276
engine/platform/android/file_access_android.cpp
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/**************************************************************************/
|
||||
/* file_access_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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "file_access_android.h"
|
||||
|
||||
#include "core/string/print_string.h"
|
||||
#include "thread_jandroid.h"
|
||||
|
||||
#include <android/asset_manager_jni.h>
|
||||
|
||||
AAssetManager *FileAccessAndroid::asset_manager = nullptr;
|
||||
jobject FileAccessAndroid::j_asset_manager = nullptr;
|
||||
|
||||
String FileAccessAndroid::get_path() const {
|
||||
return path_src;
|
||||
}
|
||||
|
||||
String FileAccessAndroid::get_path_absolute() const {
|
||||
return absolute_path;
|
||||
}
|
||||
|
||||
Error FileAccessAndroid::open_internal(const String &p_path, int p_mode_flags) {
|
||||
_close();
|
||||
|
||||
path_src = p_path;
|
||||
String path = fix_path(p_path).simplify_path();
|
||||
absolute_path = path;
|
||||
if (path.begins_with("/")) {
|
||||
path = path.substr(1, path.length());
|
||||
} else if (path.begins_with("res://")) {
|
||||
path = path.substr(6, path.length());
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, ERR_UNAVAILABLE); //can't write on android..
|
||||
asset = AAssetManager_open(asset_manager, path.utf8().get_data(), AASSET_MODE_STREAMING);
|
||||
if (!asset) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
len = AAsset_getLength(asset);
|
||||
pos = 0;
|
||||
eof = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void FileAccessAndroid::_close() {
|
||||
if (!asset) {
|
||||
return;
|
||||
}
|
||||
AAsset_close(asset);
|
||||
asset = nullptr;
|
||||
}
|
||||
|
||||
bool FileAccessAndroid::is_open() const {
|
||||
return asset != nullptr;
|
||||
}
|
||||
|
||||
void FileAccessAndroid::seek(uint64_t p_position) {
|
||||
ERR_FAIL_NULL(asset);
|
||||
|
||||
AAsset_seek(asset, p_position, SEEK_SET);
|
||||
pos = p_position;
|
||||
if (pos > len) {
|
||||
pos = len;
|
||||
eof = true;
|
||||
} else {
|
||||
eof = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessAndroid::seek_end(int64_t p_position) {
|
||||
ERR_FAIL_NULL(asset);
|
||||
AAsset_seek(asset, p_position, SEEK_END);
|
||||
pos = len + p_position;
|
||||
}
|
||||
|
||||
uint64_t FileAccessAndroid::get_position() const {
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint64_t FileAccessAndroid::get_length() const {
|
||||
return len;
|
||||
}
|
||||
|
||||
bool FileAccessAndroid::eof_reached() const {
|
||||
return eof;
|
||||
}
|
||||
|
||||
uint8_t FileAccessAndroid::get_8() const {
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t byte;
|
||||
AAsset_read(asset, &byte, 1);
|
||||
pos++;
|
||||
return byte;
|
||||
}
|
||||
|
||||
uint16_t FileAccessAndroid::get_16() const {
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t bytes = 0;
|
||||
int r = AAsset_read(asset, &bytes, 2);
|
||||
|
||||
if (r >= 0) {
|
||||
pos += r;
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
bytes = BSWAP16(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint32_t FileAccessAndroid::get_32() const {
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t bytes = 0;
|
||||
int r = AAsset_read(asset, &bytes, 4);
|
||||
|
||||
if (r >= 0) {
|
||||
pos += r;
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
bytes = BSWAP32(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint64_t FileAccessAndroid::get_64() const {
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t bytes = 0;
|
||||
int r = AAsset_read(asset, &bytes, 8);
|
||||
|
||||
if (r >= 0) {
|
||||
pos += r;
|
||||
if (pos >= len) {
|
||||
eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
bytes = BSWAP64(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint64_t FileAccessAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
|
||||
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
|
||||
|
||||
int r = AAsset_read(asset, p_dst, p_length);
|
||||
|
||||
if (pos + p_length > len) {
|
||||
eof = true;
|
||||
}
|
||||
|
||||
if (r >= 0) {
|
||||
pos += r;
|
||||
if (pos > len) {
|
||||
pos = len;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
Error FileAccessAndroid::get_error() const {
|
||||
return eof ? ERR_FILE_EOF : OK; // not sure what else it may happen
|
||||
}
|
||||
|
||||
void FileAccessAndroid::flush() {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
void FileAccessAndroid::store_8(uint8_t p_dest) {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
void FileAccessAndroid::store_16(uint16_t p_dest) {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
void FileAccessAndroid::store_32(uint32_t p_dest) {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
void FileAccessAndroid::store_64(uint64_t p_dest) {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
bool FileAccessAndroid::file_exists(const String &p_path) {
|
||||
String path = fix_path(p_path).simplify_path();
|
||||
if (path.begins_with("/")) {
|
||||
path = path.substr(1, path.length());
|
||||
} else if (path.begins_with("res://")) {
|
||||
path = path.substr(6, path.length());
|
||||
}
|
||||
|
||||
AAsset *at = AAssetManager_open(asset_manager, path.utf8().get_data(), AASSET_MODE_STREAMING);
|
||||
|
||||
if (!at) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AAsset_close(at);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileAccessAndroid::close() {
|
||||
_close();
|
||||
}
|
||||
|
||||
FileAccessAndroid::~FileAccessAndroid() {
|
||||
_close();
|
||||
}
|
||||
|
||||
void FileAccessAndroid::setup(jobject p_asset_manager) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
j_asset_manager = env->NewGlobalRef(p_asset_manager);
|
||||
asset_manager = AAssetManager_fromJava(env, j_asset_manager);
|
||||
}
|
||||
|
||||
void FileAccessAndroid::terminate() {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
|
||||
env->DeleteGlobalRef(j_asset_manager);
|
||||
}
|
||||
105
engine/platform/android/file_access_android.h
Normal file
105
engine/platform/android/file_access_android.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/**************************************************************************/
|
||||
/* file_access_android.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FILE_ACCESS_ANDROID_H
|
||||
#define FILE_ACCESS_ANDROID_H
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
|
||||
class FileAccessAndroid : public FileAccess {
|
||||
static AAssetManager *asset_manager;
|
||||
static jobject j_asset_manager;
|
||||
|
||||
mutable AAsset *asset = nullptr;
|
||||
mutable uint64_t len = 0;
|
||||
mutable uint64_t pos = 0;
|
||||
mutable bool eof = false;
|
||||
String absolute_path;
|
||||
String path_src;
|
||||
|
||||
void _close();
|
||||
|
||||
public:
|
||||
virtual Error open_internal(const String &p_path, int p_mode_flags) override; // open a file
|
||||
virtual bool is_open() const override; // true when file is open
|
||||
|
||||
/// returns the path for the current open file
|
||||
virtual String get_path() const override;
|
||||
/// returns the absolute path for the current open file
|
||||
virtual String get_path_absolute() const override;
|
||||
|
||||
virtual void seek(uint64_t p_position) override; // seek to a given position
|
||||
virtual void seek_end(int64_t p_position = 0) override; // seek from the end of file
|
||||
virtual uint64_t get_position() const override; // get position in the file
|
||||
virtual uint64_t get_length() const override; // get size of the file
|
||||
|
||||
virtual bool eof_reached() const override; // reading passed EOF
|
||||
|
||||
virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
|
||||
virtual uint8_t get_8() const override; // get a byte
|
||||
virtual uint16_t get_16() const override;
|
||||
virtual uint32_t get_32() const override;
|
||||
virtual uint64_t get_64() const override;
|
||||
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
|
||||
|
||||
virtual Error get_error() const override; // get last error
|
||||
|
||||
virtual void flush() override;
|
||||
virtual void store_8(uint8_t p_dest) override; // store a byte
|
||||
virtual void store_16(uint16_t p_dest) override;
|
||||
virtual void store_32(uint32_t p_dest) override;
|
||||
virtual void store_64(uint64_t p_dest) override;
|
||||
|
||||
virtual bool file_exists(const String &p_path) override; // return true if a file exists
|
||||
|
||||
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
|
||||
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
|
||||
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
|
||||
|
||||
virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
|
||||
virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
|
||||
virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
|
||||
virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
|
||||
|
||||
virtual void close() override;
|
||||
|
||||
static void setup(jobject p_asset_manager);
|
||||
|
||||
static void terminate();
|
||||
|
||||
~FileAccessAndroid();
|
||||
};
|
||||
|
||||
#endif // FILE_ACCESS_ANDROID_H
|
||||
436
engine/platform/android/file_access_filesystem_jandroid.cpp
Normal file
436
engine/platform/android/file_access_filesystem_jandroid.cpp
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/**************************************************************************/
|
||||
/* file_access_filesystem_jandroid.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "file_access_filesystem_jandroid.h"
|
||||
|
||||
#include "thread_jandroid.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
jobject FileAccessFilesystemJAndroid::file_access_handler = nullptr;
|
||||
jclass FileAccessFilesystemJAndroid::cls;
|
||||
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_open = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_get_size = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_seek = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_seek_end = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_read = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_tell = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_eof = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_set_eof = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_close = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_exists = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_last_modified = nullptr;
|
||||
jmethodID FileAccessFilesystemJAndroid::_file_resize = nullptr;
|
||||
|
||||
String FileAccessFilesystemJAndroid::get_path() const {
|
||||
return path_src;
|
||||
}
|
||||
|
||||
String FileAccessFilesystemJAndroid::get_path_absolute() const {
|
||||
return absolute_path;
|
||||
}
|
||||
|
||||
Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mode_flags) {
|
||||
if (is_open()) {
|
||||
_close();
|
||||
}
|
||||
|
||||
if (_file_open) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
|
||||
|
||||
String path = fix_path(p_path).simplify_path();
|
||||
jstring js = env->NewStringUTF(path.utf8().get_data());
|
||||
int res = env->CallIntMethod(file_access_handler, _file_open, js, p_mode_flags);
|
||||
env->DeleteLocalRef(js);
|
||||
|
||||
if (res <= 0) {
|
||||
switch (res) {
|
||||
case 0:
|
||||
default:
|
||||
return ERR_FILE_CANT_OPEN;
|
||||
|
||||
case -2:
|
||||
return ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
id = res;
|
||||
path_src = p_path;
|
||||
absolute_path = path;
|
||||
return OK;
|
||||
} else {
|
||||
return ERR_UNCONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::_close() {
|
||||
if (!is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_file_close) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
env->CallVoidMethod(file_access_handler, _file_close, id);
|
||||
}
|
||||
id = 0;
|
||||
}
|
||||
|
||||
bool FileAccessFilesystemJAndroid::is_open() const {
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::seek(uint64_t p_position) {
|
||||
if (_file_seek) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
|
||||
env->CallVoidMethod(file_access_handler, _file_seek, id, p_position);
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::seek_end(int64_t p_position) {
|
||||
if (_file_seek_end) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
|
||||
env->CallVoidMethod(file_access_handler, _file_seek_end, id, p_position);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t FileAccessFilesystemJAndroid::get_position() const {
|
||||
if (_file_tell) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, 0);
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
return env->CallLongMethod(file_access_handler, _file_tell, id);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t FileAccessFilesystemJAndroid::get_length() const {
|
||||
if (_file_get_size) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, 0);
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
return env->CallLongMethod(file_access_handler, _file_get_size, id);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileAccessFilesystemJAndroid::eof_reached() const {
|
||||
if (_file_eof) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), false, "File must be opened before use.");
|
||||
return env->CallBooleanMethod(file_access_handler, _file_eof, id);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::_set_eof(bool eof) {
|
||||
if (_file_set_eof) {
|
||||
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
|
||||
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
env->CallVoidMethod(file_access_handler, _file_set_eof, id, eof);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FileAccessFilesystemJAndroid::get_8() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
uint8_t byte;
|
||||
get_buffer(&byte, 1);
|
||||
return byte;
|
||||
}
|
||||
|
||||
uint16_t FileAccessFilesystemJAndroid::get_16() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
uint16_t bytes = 0;
|
||||
get_buffer(reinterpret_cast<uint8_t *>(&bytes), 2);
|
||||
if (big_endian) {
|
||||
bytes = BSWAP16(bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint32_t FileAccessFilesystemJAndroid::get_32() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
uint32_t bytes = 0;
|
||||
get_buffer(reinterpret_cast<uint8_t *>(&bytes), 4);
|
||||
if (big_endian) {
|
||||
bytes = BSWAP32(bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint64_t FileAccessFilesystemJAndroid::get_64() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
uint64_t bytes = 0;
|
||||
get_buffer(reinterpret_cast<uint8_t *>(&bytes), 8);
|
||||
if (big_endian) {
|
||||
bytes = BSWAP64(bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
String FileAccessFilesystemJAndroid::get_line() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), String(), "File must be opened before use.");
|
||||
|
||||
const size_t buffer_size_limit = 2048;
|
||||
const uint64_t file_size = get_length();
|
||||
const uint64_t start_position = get_position();
|
||||
|
||||
String result;
|
||||
LocalVector<uint8_t> line_buffer;
|
||||
size_t current_buffer_size = 0;
|
||||
uint64_t line_buffer_position = 0;
|
||||
|
||||
while (true) {
|
||||
size_t line_buffer_size = MIN(buffer_size_limit, file_size - get_position());
|
||||
if (line_buffer_size <= 0) {
|
||||
const_cast<FileAccessFilesystemJAndroid *>(this)->_set_eof(true);
|
||||
break;
|
||||
}
|
||||
|
||||
current_buffer_size += line_buffer_size;
|
||||
line_buffer.resize(current_buffer_size);
|
||||
|
||||
uint64_t bytes_read = get_buffer(&line_buffer[line_buffer_position], current_buffer_size - line_buffer_position);
|
||||
if (bytes_read <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (; bytes_read > 0; line_buffer_position++, bytes_read--) {
|
||||
uint8_t elem = line_buffer[line_buffer_position];
|
||||
if (elem == '\n' || elem == '\0') {
|
||||
// Found the end of the line
|
||||
const_cast<FileAccessFilesystemJAndroid *>(this)->seek(start_position + line_buffer_position + 1);
|
||||
if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) {
|
||||
return String();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) {
|
||||
return String();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t FileAccessFilesystemJAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
|
||||
if (_file_read) {
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
|
||||
if (p_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, 0);
|
||||
|
||||
jobject j_buffer = env->NewDirectByteBuffer(p_dst, p_length);
|
||||
int length = env->CallIntMethod(file_access_handler, _file_read, id, j_buffer);
|
||||
env->DeleteLocalRef(j_buffer);
|
||||
return length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::store_8(uint8_t p_dest) {
|
||||
store_buffer(&p_dest, 1);
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::store_16(uint16_t p_dest) {
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP16(p_dest);
|
||||
}
|
||||
store_buffer(reinterpret_cast<uint8_t *>(&p_dest), 2);
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::store_32(uint32_t p_dest) {
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP32(p_dest);
|
||||
}
|
||||
store_buffer(reinterpret_cast<uint8_t *>(&p_dest), 4);
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::store_64(uint64_t p_dest) {
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP64(p_dest);
|
||||
}
|
||||
store_buffer(reinterpret_cast<uint8_t *>(&p_dest), 8);
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) {
|
||||
if (_file_write) {
|
||||
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
|
||||
if (p_length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
|
||||
jobject j_buffer = env->NewDirectByteBuffer((void *)p_src, p_length);
|
||||
env->CallVoidMethod(file_access_handler, _file_write, id, j_buffer);
|
||||
env->DeleteLocalRef(j_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
Error FileAccessFilesystemJAndroid::get_error() const {
|
||||
if (eof_reached()) {
|
||||
return ERR_FILE_EOF;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error FileAccessFilesystemJAndroid::resize(int64_t p_length) {
|
||||
if (_file_resize) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, FAILED);
|
||||
ERR_FAIL_COND_V_MSG(!is_open(), FAILED, "File must be opened before use.");
|
||||
int res = env->CallIntMethod(file_access_handler, _file_resize, id, p_length);
|
||||
switch (res) {
|
||||
case 0:
|
||||
return OK;
|
||||
case -4:
|
||||
return ERR_INVALID_PARAMETER;
|
||||
case -3:
|
||||
return ERR_FILE_CANT_OPEN;
|
||||
case -2:
|
||||
return ERR_FILE_NOT_FOUND;
|
||||
case -1:
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
} else {
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::flush() {
|
||||
if (_file_flush) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
|
||||
env->CallVoidMethod(file_access_handler, _file_flush, id);
|
||||
}
|
||||
}
|
||||
|
||||
bool FileAccessFilesystemJAndroid::file_exists(const String &p_path) {
|
||||
if (_file_exists) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
|
||||
String path = fix_path(p_path).simplify_path();
|
||||
jstring js = env->NewStringUTF(path.utf8().get_data());
|
||||
bool result = env->CallBooleanMethod(file_access_handler, _file_exists, js);
|
||||
env->DeleteLocalRef(js);
|
||||
return result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t FileAccessFilesystemJAndroid::_get_modified_time(const String &p_file) {
|
||||
if (_file_last_modified) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL_V(env, false);
|
||||
|
||||
String path = fix_path(p_file).simplify_path();
|
||||
jstring js = env->NewStringUTF(path.utf8().get_data());
|
||||
uint64_t result = env->CallLongMethod(file_access_handler, _file_last_modified, js);
|
||||
env->DeleteLocalRef(js);
|
||||
return result;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
file_access_handler = env->NewGlobalRef(p_file_access_handler);
|
||||
|
||||
jclass c = env->GetObjectClass(file_access_handler);
|
||||
cls = (jclass)env->NewGlobalRef(c);
|
||||
|
||||
_file_open = env->GetMethodID(cls, "fileOpen", "(Ljava/lang/String;I)I");
|
||||
_file_get_size = env->GetMethodID(cls, "fileGetSize", "(I)J");
|
||||
_file_tell = env->GetMethodID(cls, "fileGetPosition", "(I)J");
|
||||
_file_eof = env->GetMethodID(cls, "isFileEof", "(I)Z");
|
||||
_file_set_eof = env->GetMethodID(cls, "setFileEof", "(IZ)V");
|
||||
_file_seek = env->GetMethodID(cls, "fileSeek", "(IJ)V");
|
||||
_file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V");
|
||||
_file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I");
|
||||
_file_close = env->GetMethodID(cls, "fileClose", "(I)V");
|
||||
_file_write = env->GetMethodID(cls, "fileWrite", "(ILjava/nio/ByteBuffer;)V");
|
||||
_file_flush = env->GetMethodID(cls, "fileFlush", "(I)V");
|
||||
_file_exists = env->GetMethodID(cls, "fileExists", "(Ljava/lang/String;)Z");
|
||||
_file_last_modified = env->GetMethodID(cls, "fileLastModified", "(Ljava/lang/String;)J");
|
||||
_file_resize = env->GetMethodID(cls, "fileResize", "(IJ)I");
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::terminate() {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
|
||||
env->DeleteGlobalRef(cls);
|
||||
env->DeleteGlobalRef(file_access_handler);
|
||||
}
|
||||
|
||||
void FileAccessFilesystemJAndroid::close() {
|
||||
if (is_open()) {
|
||||
_close();
|
||||
}
|
||||
}
|
||||
|
||||
FileAccessFilesystemJAndroid::FileAccessFilesystemJAndroid() {
|
||||
id = 0;
|
||||
}
|
||||
|
||||
FileAccessFilesystemJAndroid::~FileAccessFilesystemJAndroid() {
|
||||
if (is_open()) {
|
||||
_close();
|
||||
}
|
||||
}
|
||||
117
engine/platform/android/file_access_filesystem_jandroid.h
Normal file
117
engine/platform/android/file_access_filesystem_jandroid.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/**************************************************************************/
|
||||
/* file_access_filesystem_jandroid.h */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FILE_ACCESS_FILESYSTEM_JANDROID_H
|
||||
#define FILE_ACCESS_FILESYSTEM_JANDROID_H
|
||||
|
||||
#include "java_godot_lib_jni.h"
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
class FileAccessFilesystemJAndroid : public FileAccess {
|
||||
static jobject file_access_handler;
|
||||
static jclass cls;
|
||||
|
||||
static jmethodID _file_open;
|
||||
static jmethodID _file_get_size;
|
||||
static jmethodID _file_seek;
|
||||
static jmethodID _file_seek_end;
|
||||
static jmethodID _file_tell;
|
||||
static jmethodID _file_eof;
|
||||
static jmethodID _file_set_eof;
|
||||
static jmethodID _file_read;
|
||||
static jmethodID _file_write;
|
||||
static jmethodID _file_flush;
|
||||
static jmethodID _file_close;
|
||||
static jmethodID _file_exists;
|
||||
static jmethodID _file_last_modified;
|
||||
static jmethodID _file_resize;
|
||||
|
||||
int id;
|
||||
String absolute_path;
|
||||
String path_src;
|
||||
|
||||
void _close(); ///< close a file
|
||||
void _set_eof(bool eof);
|
||||
|
||||
public:
|
||||
virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
|
||||
virtual bool is_open() const override; ///< true when file is open
|
||||
|
||||
/// returns the path for the current open file
|
||||
virtual String get_path() const override;
|
||||
/// returns the absolute path for the current open file
|
||||
virtual String get_path_absolute() const override;
|
||||
|
||||
virtual void seek(uint64_t p_position) override; ///< seek to a given position
|
||||
virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
|
||||
virtual uint64_t get_position() const override; ///< get position in the file
|
||||
virtual uint64_t get_length() const override; ///< get size of the file
|
||||
|
||||
virtual bool eof_reached() const override; ///< reading passed EOF
|
||||
|
||||
virtual Error resize(int64_t p_length) override;
|
||||
virtual uint8_t get_8() const override; ///< get a byte
|
||||
virtual uint16_t get_16() const override;
|
||||
virtual uint32_t get_32() const override;
|
||||
virtual uint64_t get_64() const override;
|
||||
virtual String get_line() const override; ///< get a line
|
||||
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
|
||||
|
||||
virtual Error get_error() const override; ///< get last error
|
||||
|
||||
virtual void flush() override;
|
||||
virtual void store_8(uint8_t p_dest) override; ///< store a byte
|
||||
virtual void store_16(uint16_t p_dest) override;
|
||||
virtual void store_32(uint32_t p_dest) override;
|
||||
virtual void store_64(uint64_t p_dest) override;
|
||||
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override;
|
||||
|
||||
virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
|
||||
|
||||
static void setup(jobject p_file_access_handler);
|
||||
static void terminate();
|
||||
|
||||
virtual uint64_t _get_modified_time(const String &p_file) override;
|
||||
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
|
||||
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return FAILED; }
|
||||
|
||||
virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
|
||||
virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
|
||||
virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
|
||||
virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
|
||||
|
||||
virtual void close() override;
|
||||
|
||||
FileAccessFilesystemJAndroid();
|
||||
~FileAccessFilesystemJAndroid();
|
||||
};
|
||||
|
||||
#endif // FILE_ACCESS_FILESYSTEM_JANDROID_H
|
||||
58
engine/platform/android/java/app/AndroidManifest.xml
Normal file
58
engine/platform/android/java/app/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:installLocation="auto" >
|
||||
|
||||
<supports-screens
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:largeScreens="true"
|
||||
android:xlargeScreens="true" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00030000"
|
||||
android:required="true" />
|
||||
|
||||
<application
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/icon"
|
||||
android:appCategory="game"
|
||||
android:isGame="true"
|
||||
android:hasFragileUserData="false"
|
||||
android:requestLegacyExternalStorage="false"
|
||||
tools:ignore="GoogleAppIndexingWarning" >
|
||||
<profileable
|
||||
android:shell="true"
|
||||
android:enabled="true"
|
||||
tools:targetApi="29" />
|
||||
|
||||
<!-- Records the version of the Godot editor used for building -->
|
||||
<meta-data
|
||||
android:name="org.godotengine.editor.version"
|
||||
android:value="${godotEditorVersion}" />
|
||||
|
||||
<activity
|
||||
android:name=".GodotApp"
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:theme="@style/GodotAppSplashTheme"
|
||||
android:launchMode="singleInstancePerTask"
|
||||
android:excludeFromRecents="false"
|
||||
android:exported="true"
|
||||
android:screenOrientation="landscape"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:resizeableActivity="false"
|
||||
tools:ignore="UnusedAttribute" >
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
plugins {
|
||||
id 'com.android.asset-pack'
|
||||
}
|
||||
|
||||
assetPack {
|
||||
packName = "installTime" // Directory name for the asset pack
|
||||
dynamicDelivery {
|
||||
deliveryType = "install-time" // Delivery mode
|
||||
}
|
||||
}
|
||||
2
engine/platform/android/java/app/assets/.gitignore
vendored
Normal file
2
engine/platform/android/java/app/assets/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
301
engine/platform/android/java/app/build.gradle
Normal file
301
engine/platform/android/java/app/build.gradle
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
// Gradle build config for Godot Engine's Android port.
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
apply from: 'config.gradle'
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
|
||||
// Godot user plugins custom maven repos
|
||||
String[] mavenRepos = getGodotPluginsMavenRepos()
|
||||
if (mavenRepos != null && mavenRepos.size() > 0) {
|
||||
for (String repoUrl : mavenRepos) {
|
||||
maven {
|
||||
url repoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
// Initializes a placeholder for the devImplementation dependency configuration.
|
||||
devImplementation {}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
||||
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
||||
|
||||
if (rootProject.findProject(":lib")) {
|
||||
implementation project(":lib")
|
||||
} else if (rootProject.findProject(":godot:lib")) {
|
||||
implementation project(":godot:lib")
|
||||
} else {
|
||||
// Godot gradle build mode. In this scenario this project is the only one around and the Godot
|
||||
// library is available through the pre-generated godot-lib.*.aar android archive files.
|
||||
debugImplementation fileTree(dir: 'libs/debug', include: ['*.jar', '*.aar'])
|
||||
devImplementation fileTree(dir: 'libs/dev', include: ['*.jar', '*.aar'])
|
||||
releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar'])
|
||||
}
|
||||
|
||||
// Godot user plugins remote dependencies
|
||||
String[] remoteDeps = getGodotPluginsRemoteBinaries()
|
||||
if (remoteDeps != null && remoteDeps.size() > 0) {
|
||||
for (String dep : remoteDeps) {
|
||||
implementation dep
|
||||
}
|
||||
}
|
||||
|
||||
// Godot user plugins local dependencies
|
||||
String[] pluginsBinaries = getGodotPluginsLocalBinaries()
|
||||
if (pluginsBinaries != null && pluginsBinaries.size() > 0) {
|
||||
implementation files(pluginsBinaries)
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
buildToolsVersion versions.buildTools
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.javaVersion
|
||||
targetCompatibility versions.javaVersion
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = versions.javaVersion
|
||||
}
|
||||
|
||||
assetPacks = [":assetPacks:installTime"]
|
||||
|
||||
namespace = 'com.godot.game'
|
||||
|
||||
defaultConfig {
|
||||
// The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
|
||||
aaptOptions {
|
||||
ignoreAssetsPattern "!.svn:!.git:!.gitignore:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
|
||||
}
|
||||
|
||||
ndk {
|
||||
String[] export_abi_list = getExportEnabledABIs()
|
||||
abiFilters export_abi_list
|
||||
}
|
||||
|
||||
manifestPlaceholders = [godotEditorVersion: getGodotEditorVersion()]
|
||||
|
||||
// Feel free to modify the application id to your own.
|
||||
applicationId getExportPackageName()
|
||||
versionCode getExportVersionCode()
|
||||
versionName getExportVersionName()
|
||||
minSdkVersion getExportMinSdkVersion()
|
||||
targetSdkVersion getExportTargetSdkVersion()
|
||||
|
||||
missingDimensionStrategy 'products', 'template'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
disable 'MissingTranslation', 'UnusedResources'
|
||||
}
|
||||
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE'
|
||||
exclude 'META-INF/NOTICE'
|
||||
|
||||
// 'doNotStrip' is enabled for development within Android Studio
|
||||
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()
|
||||
}
|
||||
|
||||
// Always select Godot's version of libc++_shared.so in case deps have their own
|
||||
pickFirst 'lib/x86/libc++_shared.so'
|
||||
pickFirst 'lib/x86_64/libc++_shared.so'
|
||||
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
|
||||
pickFirst 'lib/arm64-v8a/libc++_shared.so'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
if (hasCustomDebugKeystore()) {
|
||||
storeFile new File(getDebugKeystoreFile())
|
||||
storePassword getDebugKeystorePassword()
|
||||
keyAlias getDebugKeyAlias()
|
||||
keyPassword getDebugKeystorePassword()
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
File keystoreFile = new File(getReleaseKeystoreFile())
|
||||
if (keystoreFile.isFile()) {
|
||||
storeFile keystoreFile
|
||||
storePassword getReleaseKeystorePassword()
|
||||
keyAlias getReleaseKeyAlias()
|
||||
keyPassword getReleaseKeystorePassword()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
||||
debug {
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for Godot gradle builds.
|
||||
zipAlignEnabled shouldZipAlign()
|
||||
if (shouldSign()) {
|
||||
signingConfig signingConfigs.debug
|
||||
} else {
|
||||
signingConfig null
|
||||
}
|
||||
}
|
||||
|
||||
dev {
|
||||
initWith debug
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for Godot gradle builds.
|
||||
zipAlignEnabled shouldZipAlign()
|
||||
if (shouldSign()) {
|
||||
signingConfig signingConfigs.debug
|
||||
} else {
|
||||
signingConfig null
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for Godot gradle builds.
|
||||
zipAlignEnabled shouldZipAlign()
|
||||
if (shouldSign()) {
|
||||
signingConfig signingConfigs.release
|
||||
} else {
|
||||
signingConfig null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
aidl.srcDirs = ['aidl']
|
||||
assets.srcDirs = ['assets']
|
||||
}
|
||||
debug.jniLibs.srcDirs = ['libs/debug', 'libs/debug/vulkan_validation_layers']
|
||||
dev.jniLibs.srcDirs = ['libs/dev']
|
||||
release.jniLibs.srcDirs = ['libs/release']
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all { output ->
|
||||
output.outputFileName = "android_${variant.name}.apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task copyAndRenameDebugApk(type: Copy) {
|
||||
// The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
|
||||
// and directories. Otherwise this check may cause permissions access failures on Windows
|
||||
// machines.
|
||||
doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
|
||||
|
||||
from "$buildDir/outputs/apk/debug/android_debug.apk"
|
||||
into getExportPath()
|
||||
rename "android_debug.apk", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameDevApk(type: Copy) {
|
||||
// The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
|
||||
// and directories. Otherwise this check may cause permissions access failures on Windows
|
||||
// machines.
|
||||
doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
|
||||
|
||||
from "$buildDir/outputs/apk/dev/android_dev.apk"
|
||||
into getExportPath()
|
||||
rename "android_dev.apk", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameReleaseApk(type: Copy) {
|
||||
// The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
|
||||
// and directories. Otherwise this check may cause permissions access failures on Windows
|
||||
// machines.
|
||||
doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
|
||||
|
||||
from "$buildDir/outputs/apk/release/android_release.apk"
|
||||
into getExportPath()
|
||||
rename "android_release.apk", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameDebugAab(type: Copy) {
|
||||
// The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
|
||||
// and directories. Otherwise this check may cause permissions access failures on Windows
|
||||
// machines.
|
||||
doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
|
||||
|
||||
from "$buildDir/outputs/bundle/debug/build-debug.aab"
|
||||
into getExportPath()
|
||||
rename "build-debug.aab", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameDevAab(type: Copy) {
|
||||
// The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
|
||||
// and directories. Otherwise this check may cause permissions access failures on Windows
|
||||
// machines.
|
||||
doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
|
||||
|
||||
from "$buildDir/outputs/bundle/dev/build-dev.aab"
|
||||
into getExportPath()
|
||||
rename "build-dev.aab", getExportFilename()
|
||||
}
|
||||
|
||||
task copyAndRenameReleaseAab(type: Copy) {
|
||||
// The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
|
||||
// and directories. Otherwise this check may cause permissions access failures on Windows
|
||||
// machines.
|
||||
doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
|
||||
|
||||
from "$buildDir/outputs/bundle/release/build-release.aab"
|
||||
into getExportPath()
|
||||
rename "build-release.aab", getExportFilename()
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to validate the version of the Java SDK used for the Godot gradle builds.
|
||||
*/
|
||||
task validateJavaVersion {
|
||||
if (JavaVersion.current() != versions.javaVersion) {
|
||||
throw new GradleException("Invalid Java version ${JavaVersion.current()}. Version ${versions.javaVersion} is the required Java version for Godot gradle builds.")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When they're scheduled to run, the copy*AARToAppModule tasks generate dependencies for the 'app'
|
||||
module, so we're ensuring the ':app:preBuild' task is set to run after those tasks.
|
||||
*/
|
||||
if (rootProject.tasks.findByPath("copyDebugAARToAppModule") != null) {
|
||||
preBuild.mustRunAfter(rootProject.tasks.named("copyDebugAARToAppModule"))
|
||||
}
|
||||
if (rootProject.tasks.findByPath("copyDevAARToAppModule") != null) {
|
||||
preBuild.mustRunAfter(rootProject.tasks.named("copyDevAARToAppModule"))
|
||||
}
|
||||
if (rootProject.tasks.findByPath("copyReleaseAARToAppModule") != null) {
|
||||
preBuild.mustRunAfter(rootProject.tasks.named("copyReleaseAARToAppModule"))
|
||||
}
|
||||
386
engine/platform/android/java/app/config.gradle
Normal file
386
engine/platform/android/java/app/config.gradle
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
ext.versions = [
|
||||
androidGradlePlugin: '8.2.0',
|
||||
compileSdk : 34,
|
||||
// Also update 'platform/android/export/export_plugin.cpp#OPENGL_MIN_SDK_VERSION'
|
||||
minSdk : 21,
|
||||
// Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
|
||||
targetSdk : 34,
|
||||
buildTools : '34.0.0',
|
||||
kotlinVersion : '1.9.20',
|
||||
fragmentVersion : '1.7.1',
|
||||
nexusPublishVersion: '1.3.0',
|
||||
javaVersion : JavaVersion.VERSION_17,
|
||||
// Also update 'platform/android/detect.py#get_ndk_version()' when this is updated.
|
||||
ndkVersion : '23.2.8568313',
|
||||
splashscreenVersion: '1.0.1'
|
||||
|
||||
]
|
||||
|
||||
ext.getExportPackageName = { ->
|
||||
// Retrieve the app id from the project property set by the Godot build command.
|
||||
String appId = project.hasProperty("export_package_name") ? project.property("export_package_name") : ""
|
||||
// Check if the app id is valid, otherwise use the default.
|
||||
if (appId == null || appId.isEmpty()) {
|
||||
appId = "com.godot.game"
|
||||
}
|
||||
return appId
|
||||
}
|
||||
|
||||
ext.getExportVersionCode = { ->
|
||||
String versionCode = project.hasProperty("export_version_code") ? project.property("export_version_code") : ""
|
||||
if (versionCode == null || versionCode.isEmpty()) {
|
||||
versionCode = "1"
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(versionCode)
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
ext.getExportVersionName = { ->
|
||||
String versionName = project.hasProperty("export_version_name") ? project.property("export_version_name") : ""
|
||||
if (versionName == null || versionName.isEmpty()) {
|
||||
versionName = "1.0"
|
||||
}
|
||||
return versionName
|
||||
}
|
||||
|
||||
ext.getExportMinSdkVersion = { ->
|
||||
String minSdkVersion = project.hasProperty("export_version_min_sdk") ? project.property("export_version_min_sdk") : ""
|
||||
if (minSdkVersion == null || minSdkVersion.isEmpty()) {
|
||||
minSdkVersion = "$versions.minSdk"
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(minSdkVersion)
|
||||
} catch (NumberFormatException ignored) {
|
||||
return versions.minSdk
|
||||
}
|
||||
}
|
||||
|
||||
ext.getExportTargetSdkVersion = { ->
|
||||
String targetSdkVersion = project.hasProperty("export_version_target_sdk") ? project.property("export_version_target_sdk") : ""
|
||||
if (targetSdkVersion == null || targetSdkVersion.isEmpty()) {
|
||||
targetSdkVersion = "$versions.targetSdk"
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(targetSdkVersion)
|
||||
} catch (NumberFormatException ignored) {
|
||||
return versions.targetSdk
|
||||
}
|
||||
}
|
||||
|
||||
ext.getGodotEditorVersion = { ->
|
||||
String editorVersion = project.hasProperty("godot_editor_version") ? project.property("godot_editor_version") : ""
|
||||
if (editorVersion == null || editorVersion.isEmpty()) {
|
||||
// Try the library version first
|
||||
editorVersion = getGodotLibraryVersionName()
|
||||
|
||||
if (editorVersion.isEmpty()) {
|
||||
// Fallback value.
|
||||
editorVersion = "custom_build"
|
||||
}
|
||||
}
|
||||
return editorVersion
|
||||
}
|
||||
|
||||
ext.getGodotLibraryVersionCode = { ->
|
||||
String versionName = ""
|
||||
int versionCode = 1
|
||||
(versionName, versionCode) = getGodotLibraryVersion()
|
||||
return versionCode
|
||||
}
|
||||
|
||||
ext.getGodotLibraryVersionName = { ->
|
||||
String versionName = ""
|
||||
int versionCode = 1
|
||||
(versionName, versionCode) = getGodotLibraryVersion()
|
||||
return versionName
|
||||
}
|
||||
|
||||
ext.generateGodotLibraryVersion = { List<String> requiredKeys ->
|
||||
// Attempt to read the version from the `version.py` file.
|
||||
String libraryVersionName = ""
|
||||
int libraryVersionCode = 0
|
||||
|
||||
File versionFile = new File("../../../version.py")
|
||||
if (versionFile.isFile()) {
|
||||
def map = [:]
|
||||
|
||||
List<String> lines = versionFile.readLines()
|
||||
for (String line in lines) {
|
||||
String[] keyValue = line.split("=")
|
||||
String key = keyValue[0].trim()
|
||||
String value = keyValue[1].trim().replaceAll("\"", "")
|
||||
|
||||
if (requiredKeys.contains(key)) {
|
||||
if (!value.isEmpty()) {
|
||||
map[key] = value
|
||||
}
|
||||
requiredKeys.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredKeys.empty) {
|
||||
libraryVersionName = map.values().join(".")
|
||||
try {
|
||||
if (map.containsKey("status")) {
|
||||
int statusCode = 0
|
||||
String statusValue = map["status"]
|
||||
if (statusValue == null) {
|
||||
statusCode = 0
|
||||
} else if (statusValue.startsWith("dev")) {
|
||||
statusCode = 1
|
||||
} else if (statusValue.startsWith("alpha")) {
|
||||
statusCode = 2
|
||||
} else if (statusValue.startsWith("beta")) {
|
||||
statusCode = 3
|
||||
} else if (statusValue.startsWith("rc")) {
|
||||
statusCode = 4
|
||||
} else if (statusValue.startsWith("stable")) {
|
||||
statusCode = 5
|
||||
} else {
|
||||
statusCode = 0
|
||||
}
|
||||
|
||||
libraryVersionCode = statusCode
|
||||
}
|
||||
|
||||
if (map.containsKey("patch")) {
|
||||
libraryVersionCode += Integer.parseInt(map["patch"]) * 10
|
||||
}
|
||||
|
||||
if (map.containsKey("minor")) {
|
||||
libraryVersionCode += (Integer.parseInt(map["minor"]) * 1000)
|
||||
}
|
||||
|
||||
if (map.containsKey("major")) {
|
||||
libraryVersionCode += (Integer.parseInt(map["major"]) * 100000)
|
||||
}
|
||||
} catch (NumberFormatException ignore) {
|
||||
libraryVersionCode = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (libraryVersionName.isEmpty()) {
|
||||
// Fallback value in case we're unable to read the file.
|
||||
libraryVersionName = "custom_build"
|
||||
}
|
||||
|
||||
if (libraryVersionCode == 0) {
|
||||
libraryVersionCode = 1
|
||||
}
|
||||
|
||||
return [libraryVersionName, libraryVersionCode]
|
||||
}
|
||||
|
||||
ext.getGodotLibraryVersion = { ->
|
||||
List<String> requiredKeys = ["major", "minor", "patch", "status", "module_config"]
|
||||
return generateGodotLibraryVersion(requiredKeys)
|
||||
}
|
||||
|
||||
ext.getGodotPublishVersion = { ->
|
||||
List<String> requiredKeys = ["major", "minor", "patch", "status"]
|
||||
String versionName = ""
|
||||
int versionCode = 1
|
||||
(versionName, versionCode) = generateGodotLibraryVersion(requiredKeys)
|
||||
if (!versionName.endsWith("stable")) {
|
||||
versionName += "-SNAPSHOT"
|
||||
}
|
||||
return versionName
|
||||
}
|
||||
|
||||
final String VALUE_SEPARATOR_REGEX = "\\|"
|
||||
|
||||
// get the list of ABIs the project should be exported to
|
||||
ext.getExportEnabledABIs = { ->
|
||||
String enabledABIs = project.hasProperty("export_enabled_abis") ? project.property("export_enabled_abis") : ""
|
||||
if (enabledABIs == null || enabledABIs.isEmpty()) {
|
||||
enabledABIs = "armeabi-v7a|arm64-v8a|x86|x86_64|"
|
||||
}
|
||||
Set<String> exportAbiFilter = []
|
||||
for (String abi_name : enabledABIs.split(VALUE_SEPARATOR_REGEX)) {
|
||||
if (!abi_name.trim().isEmpty()){
|
||||
exportAbiFilter.add(abi_name)
|
||||
}
|
||||
}
|
||||
return exportAbiFilter
|
||||
}
|
||||
|
||||
ext.getExportPath = {
|
||||
String exportPath = project.hasProperty("export_path") ? project.property("export_path") : ""
|
||||
if (exportPath == null || exportPath.isEmpty()) {
|
||||
exportPath = "."
|
||||
}
|
||||
return exportPath
|
||||
}
|
||||
|
||||
ext.getExportFilename = {
|
||||
String exportFilename = project.hasProperty("export_filename") ? project.property("export_filename") : ""
|
||||
if (exportFilename == null || exportFilename.isEmpty()) {
|
||||
exportFilename = "godot_android"
|
||||
}
|
||||
return exportFilename
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the project properties for the 'plugins_maven_repos' property and return the list
|
||||
* of maven repos.
|
||||
*/
|
||||
ext.getGodotPluginsMavenRepos = { ->
|
||||
Set<String> mavenRepos = []
|
||||
|
||||
// Retrieve the list of maven repos.
|
||||
if (project.hasProperty("plugins_maven_repos")) {
|
||||
String mavenReposProperty = project.property("plugins_maven_repos")
|
||||
if (mavenReposProperty != null && !mavenReposProperty.trim().isEmpty()) {
|
||||
for (String mavenRepoUrl : mavenReposProperty.split(VALUE_SEPARATOR_REGEX)) {
|
||||
mavenRepos += mavenRepoUrl.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mavenRepos
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the project properties for the 'plugins_remote_binaries' property and return
|
||||
* it for inclusion in the build dependencies.
|
||||
*/
|
||||
ext.getGodotPluginsRemoteBinaries = { ->
|
||||
Set<String> remoteDeps = []
|
||||
|
||||
// Retrieve the list of remote plugins binaries.
|
||||
if (project.hasProperty("plugins_remote_binaries")) {
|
||||
String remoteDepsList = project.property("plugins_remote_binaries")
|
||||
if (remoteDepsList != null && !remoteDepsList.trim().isEmpty()) {
|
||||
for (String dep: remoteDepsList.split(VALUE_SEPARATOR_REGEX)) {
|
||||
remoteDeps += dep.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
return remoteDeps
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the project properties for the 'plugins_local_binaries' property and return
|
||||
* their binaries for inclusion in the build dependencies.
|
||||
*/
|
||||
ext.getGodotPluginsLocalBinaries = { ->
|
||||
Set<String> binDeps = []
|
||||
|
||||
// Retrieve the list of local plugins binaries.
|
||||
if (project.hasProperty("plugins_local_binaries")) {
|
||||
String pluginsList = project.property("plugins_local_binaries")
|
||||
if (pluginsList != null && !pluginsList.trim().isEmpty()) {
|
||||
for (String plugin : pluginsList.split(VALUE_SEPARATOR_REGEX)) {
|
||||
binDeps += plugin.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return binDeps
|
||||
}
|
||||
|
||||
ext.getDebugKeystoreFile = { ->
|
||||
String keystoreFile = project.hasProperty("debug_keystore_file") ? project.property("debug_keystore_file") : ""
|
||||
if (keystoreFile == null || keystoreFile.isEmpty()) {
|
||||
keystoreFile = "."
|
||||
}
|
||||
return keystoreFile
|
||||
}
|
||||
|
||||
ext.hasCustomDebugKeystore = { ->
|
||||
File keystoreFile = new File(getDebugKeystoreFile())
|
||||
return keystoreFile.isFile()
|
||||
}
|
||||
|
||||
ext.getDebugKeystorePassword = { ->
|
||||
String keystorePassword = project.hasProperty("debug_keystore_password") ? project.property("debug_keystore_password") : ""
|
||||
if (keystorePassword == null || keystorePassword.isEmpty()) {
|
||||
keystorePassword = "android"
|
||||
}
|
||||
return keystorePassword
|
||||
}
|
||||
|
||||
ext.getDebugKeyAlias = { ->
|
||||
String keyAlias = project.hasProperty("debug_keystore_alias") ? project.property("debug_keystore_alias") : ""
|
||||
if (keyAlias == null || keyAlias.isEmpty()) {
|
||||
keyAlias = "androiddebugkey"
|
||||
}
|
||||
return keyAlias
|
||||
}
|
||||
|
||||
ext.getReleaseKeystoreFile = { ->
|
||||
String keystoreFile = project.hasProperty("release_keystore_file") ? project.property("release_keystore_file") : ""
|
||||
if (keystoreFile == null || keystoreFile.isEmpty()) {
|
||||
keystoreFile = "."
|
||||
}
|
||||
return keystoreFile
|
||||
}
|
||||
|
||||
ext.getReleaseKeystorePassword = { ->
|
||||
String keystorePassword = project.hasProperty("release_keystore_password") ? project.property("release_keystore_password") : ""
|
||||
return keystorePassword
|
||||
}
|
||||
|
||||
ext.getReleaseKeyAlias = { ->
|
||||
String keyAlias = project.hasProperty("release_keystore_alias") ? project.property("release_keystore_alias") : ""
|
||||
return keyAlias
|
||||
}
|
||||
|
||||
ext.isAndroidStudio = { ->
|
||||
return project.hasProperty('android.injected.invoked.from.ide')
|
||||
}
|
||||
|
||||
ext.shouldZipAlign = { ->
|
||||
String zipAlignFlag = project.hasProperty("perform_zipalign") ? project.property("perform_zipalign") : ""
|
||||
if (zipAlignFlag == null || zipAlignFlag.isEmpty()) {
|
||||
if (isAndroidStudio()) {
|
||||
zipAlignFlag = "true"
|
||||
} else {
|
||||
zipAlignFlag = "false"
|
||||
}
|
||||
}
|
||||
return Boolean.parseBoolean(zipAlignFlag)
|
||||
}
|
||||
|
||||
ext.shouldSign = { ->
|
||||
String signFlag = project.hasProperty("perform_signing") ? project.property("perform_signing") : ""
|
||||
if (signFlag == null || signFlag.isEmpty()) {
|
||||
if (isAndroidStudio()) {
|
||||
signFlag = "true"
|
||||
} else {
|
||||
signFlag = "false"
|
||||
}
|
||||
}
|
||||
return Boolean.parseBoolean(signFlag)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
28
engine/platform/android/java/app/gradle.properties
Normal file
28
engine/platform/android/java/app/gradle.properties
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Godot gradle build settings.
|
||||
# These properties apply when running a gradle build from the Godot editor.
|
||||
# NOTE: This should be kept in sync with 'godot/platform/android/java/gradle.properties' except
|
||||
# where otherwise specified.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# https://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx4536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# https://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
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
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-ar</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-bg</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-ca</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-cs</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-da</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-de</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-el</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-en</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-es_ES</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-es</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-fa</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-fi</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-fr</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-hi</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-hr</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-hu</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-in</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-it</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-iw</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-ja</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-ko</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-lt</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-lv</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-nb</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-nl</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-pl</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-pt</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-ro</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-ru</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-sk</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-sl</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-sr</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-sv</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-th</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-tl</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-tr</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-uk</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-vi</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-zh_HK</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-zh_TW</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name-zh</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME-->
|
||||
<resources>
|
||||
<string name="godot_project_name_string">godot-project-name</string>
|
||||
</resources>
|
||||
19
engine/platform/android/java/app/res/values/themes.xml
Normal file
19
engine/platform/android/java/app/res/values/themes.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="GodotAppMainTheme" parent="@android:style/Theme.Black.NoTitleBar"/>
|
||||
|
||||
<style name="GodotAppSplashTheme" parent="Theme.SplashScreen">
|
||||
<!-- Set the splash screen background, animated icon, and animation
|
||||
duration. -->
|
||||
<item name="android:windowSplashScreenBackground">@mipmap/icon_background</item>
|
||||
|
||||
<!-- Use windowSplashScreenAnimatedIcon to add a drawable or an animated
|
||||
drawable. One of these is required. -->
|
||||
<item name="windowSplashScreenAnimatedIcon">@mipmap/icon_foreground</item>
|
||||
|
||||
<!-- Set the theme of the Activity that directly follows your splash
|
||||
screen. This is required. -->
|
||||
<item name="postSplashScreenTheme">@style/GodotAppMainTheme</item>
|
||||
</style>
|
||||
</resources>
|
||||
17
engine/platform/android/java/app/settings.gradle
Normal file
17
engine/platform/android/java/app/settings.gradle
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// This is the root directory of the Godot Android gradle build.
|
||||
pluginManagement {
|
||||
apply from: 'config.gradle'
|
||||
|
||||
plugins {
|
||||
id 'com.android.application' version versions.androidGradlePlugin
|
||||
id 'org.jetbrains.kotlin.android' version versions.kotlinVersion
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
}
|
||||
|
||||
include ':assetPacks:installTime'
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/**************************************************************************/
|
||||
/* GodotApp.java */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package com.godot.game;
|
||||
|
||||
import org.godotengine.godot.GodotActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.core.splashscreen.SplashScreen;
|
||||
|
||||
/**
|
||||
* Template activity for Godot Android builds.
|
||||
* Feel free to extend and modify this class for your custom logic.
|
||||
*/
|
||||
public class GodotApp extends GodotActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
SplashScreen.installSplashScreen(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
366
engine/platform/android/java/build.gradle
Normal file
366
engine/platform/android/java/build.gradle
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
plugins {
|
||||
id 'io.github.gradle-nexus.publish-plugin'
|
||||
}
|
||||
|
||||
apply from: 'app/config.gradle'
|
||||
apply from: 'scripts/publish-root.gradle'
|
||||
|
||||
ext {
|
||||
PUBLISH_VERSION = getGodotPublishVersion()
|
||||
}
|
||||
|
||||
group = ossrhGroupId
|
||||
version = PUBLISH_VERSION
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"]
|
||||
supportedFlavors = ["editor", "template"]
|
||||
supportedFlavorsBuildTypes = [
|
||||
"editor": ["dev", "debug", "release"],
|
||||
"template": ["dev", "debug", "release"]
|
||||
]
|
||||
|
||||
// Used by gradle to specify which architecture to build for by default when running
|
||||
// `./gradlew build` (this command is usually used by Android Studio).
|
||||
// If building manually on the command line, it's recommended to use the
|
||||
// `./gradlew generateGodotTemplates` build command instead after running the `scons` command(s).
|
||||
// The {selectedAbis} values must be from the {supportedAbis} values.
|
||||
selectedAbis = ["arm64"]
|
||||
}
|
||||
|
||||
def rootDir = "../../.."
|
||||
def binDir = "$rootDir/bin/"
|
||||
def androidEditorBuildsDir = "$binDir/android_editor_builds/"
|
||||
|
||||
def getSconsTaskName(String flavor, String buildType, String abi) {
|
||||
return "compileGodotNativeLibs" + flavor.capitalize() + buildType.capitalize() + abi.capitalize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the generated 'android_debug.apk' binary template into the Godot bin directory.
|
||||
* Depends on the app build task to ensure the binary is generated prior to copying.
|
||||
*/
|
||||
task copyDebugBinaryToBin(type: Copy) {
|
||||
dependsOn ':app:assembleDebug'
|
||||
from('app/build/outputs/apk/debug')
|
||||
into(binDir)
|
||||
include('android_debug.apk')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the generated 'android_dev.apk' binary template into the Godot bin directory.
|
||||
* Depends on the app build task to ensure the binary is generated prior to copying.
|
||||
*/
|
||||
task copyDevBinaryToBin(type: Copy) {
|
||||
dependsOn ':app:assembleDev'
|
||||
from('app/build/outputs/apk/dev')
|
||||
into(binDir)
|
||||
include('android_dev.apk')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the generated 'android_release.apk' binary template into the Godot bin directory.
|
||||
* Depends on the app build task to ensure the binary is generated prior to copying.
|
||||
*/
|
||||
task copyReleaseBinaryToBin(type: Copy) {
|
||||
dependsOn ':app:assembleRelease'
|
||||
from('app/build/outputs/apk/release')
|
||||
into(binDir)
|
||||
include('android_release.apk')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive debug file into the app module debug libs directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDebugAARToAppModule(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateDebug'
|
||||
from('lib/build/outputs/aar')
|
||||
into('app/libs/debug')
|
||||
include('godot-lib.template_debug.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive debug file into the root bin directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDebugAARToBin(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateDebug'
|
||||
from('lib/build/outputs/aar')
|
||||
into(binDir)
|
||||
include('godot-lib.template_debug.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive dev file into the app module dev libs directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDevAARToAppModule(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateDev'
|
||||
from('lib/build/outputs/aar')
|
||||
into('app/libs/dev')
|
||||
include('godot-lib.template_debug.dev.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive dev file into the root bin directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyDevAARToBin(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateDev'
|
||||
from('lib/build/outputs/aar')
|
||||
into(binDir)
|
||||
include('godot-lib.template_debug.dev.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive release file into the app module release libs directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyReleaseAARToAppModule(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateRelease'
|
||||
from('lib/build/outputs/aar')
|
||||
into('app/libs/release')
|
||||
include('godot-lib.template_release.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the Godot android library archive release file into the root bin directory.
|
||||
* Depends on the library build task to ensure the AAR file is generated prior to copying.
|
||||
*/
|
||||
task copyReleaseAARToBin(type: Copy) {
|
||||
dependsOn ':lib:assembleTemplateRelease'
|
||||
from('lib/build/outputs/aar')
|
||||
into(binDir)
|
||||
include('godot-lib.template_release.aar')
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Godot gradle build template by zipping the source files from the app directory, as well
|
||||
* as the AAR files generated by 'copyDebugAAR', 'copyDevAAR' and 'copyReleaseAAR'.
|
||||
* The zip file also includes some gradle tools to enable gradle builds from the Godot Editor.
|
||||
*/
|
||||
task zipGradleBuild(type: Zip) {
|
||||
onlyIf { generateGodotTemplates.state.executed || generateDevTemplate.state.executed }
|
||||
doFirst {
|
||||
logger.lifecycle("Generating Godot gradle build template")
|
||||
}
|
||||
from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradlew', 'gradlew.bat', 'gradle/**']))
|
||||
include '**/*'
|
||||
archiveFileName = 'android_source.zip'
|
||||
destinationDirectory = file(binDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the scons build tasks responsible for generating the Godot native shared
|
||||
* libraries should be excluded.
|
||||
*/
|
||||
def excludeSconsBuildTasks() {
|
||||
return !isAndroidStudio() && !project.hasProperty("generateNativeLibs")
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the list of build tasks that should be excluded from the build process.\
|
||||
*/
|
||||
def templateExcludedBuildTask() {
|
||||
// We exclude these gradle tasks so we can run the scons command manually.
|
||||
def excludedTasks = []
|
||||
if (excludeSconsBuildTasks()) {
|
||||
logger.lifecycle("Excluding Android studio build tasks")
|
||||
for (String flavor : supportedFlavors) {
|
||||
String[] supportedBuildTypes = supportedFlavorsBuildTypes[flavor]
|
||||
for (String buildType : supportedBuildTypes) {
|
||||
for (String abi : selectedAbis) {
|
||||
excludedTasks += ":lib:" + getSconsTaskName(flavor, buildType, abi)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return excludedTasks
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the build tasks for the given flavor
|
||||
* @param flavor Must be one of the supported flavors ('template' / 'editor')
|
||||
*/
|
||||
def generateBuildTasks(String flavor = "template") {
|
||||
if (!supportedFlavors.contains(flavor)) {
|
||||
throw new GradleException("Invalid build flavor: $flavor")
|
||||
}
|
||||
|
||||
def tasks = []
|
||||
|
||||
// Only build the apks and aar files for which we have native shared libraries unless we intend
|
||||
// to run the scons build tasks.
|
||||
boolean excludeSconsBuildTasks = excludeSconsBuildTasks()
|
||||
boolean isTemplate = flavor == "template"
|
||||
String libsDir = isTemplate ? "lib/libs/" : "lib/libs/tools/"
|
||||
for (String target : supportedFlavorsBuildTypes[flavor]) {
|
||||
File targetLibs = new File(libsDir + target)
|
||||
if (!excludeSconsBuildTasks || (targetLibs != null
|
||||
&& targetLibs.isDirectory()
|
||||
&& targetLibs.listFiles() != null
|
||||
&& targetLibs.listFiles().length > 0)) {
|
||||
String capitalizedTarget = target.capitalize()
|
||||
if (isTemplate) {
|
||||
// Copy the generated aar library files to the build directory.
|
||||
tasks += "copy${capitalizedTarget}AARToAppModule"
|
||||
// Copy the generated aar library files to the bin directory.
|
||||
tasks += "copy${capitalizedTarget}AARToBin"
|
||||
// Copy the prebuilt binary templates to the bin directory.
|
||||
tasks += "copy${capitalizedTarget}BinaryToBin"
|
||||
} else {
|
||||
// Copy the generated editor apk to the bin directory.
|
||||
tasks += "copyEditor${capitalizedTarget}ApkToBin"
|
||||
// Copy the generated editor aab to the bin directory.
|
||||
tasks += "copyEditor${capitalizedTarget}AabToBin"
|
||||
}
|
||||
} else {
|
||||
logger.lifecycle("No native shared libs for target $target. Skipping build.")
|
||||
}
|
||||
}
|
||||
|
||||
return tasks
|
||||
}
|
||||
|
||||
task copyEditorReleaseApkToBin(type: Copy) {
|
||||
dependsOn ':editor:assembleRelease'
|
||||
from('editor/build/outputs/apk/release')
|
||||
into(androidEditorBuildsDir)
|
||||
include('android_editor-release*.apk')
|
||||
}
|
||||
|
||||
task copyEditorReleaseAabToBin(type: Copy) {
|
||||
dependsOn ':editor:bundleRelease'
|
||||
from('editor/build/outputs/bundle/release')
|
||||
into(androidEditorBuildsDir)
|
||||
include('android_editor-release*.aab')
|
||||
}
|
||||
|
||||
task copyEditorDebugApkToBin(type: Copy) {
|
||||
dependsOn ':editor:assembleDebug'
|
||||
from('editor/build/outputs/apk/debug')
|
||||
into(androidEditorBuildsDir)
|
||||
include('android_editor-debug.apk')
|
||||
}
|
||||
|
||||
task copyEditorDebugAabToBin(type: Copy) {
|
||||
dependsOn ':editor:bundleDebug'
|
||||
from('editor/build/outputs/bundle/debug')
|
||||
into(androidEditorBuildsDir)
|
||||
include('android_editor-debug.aab')
|
||||
}
|
||||
|
||||
task copyEditorDevApkToBin(type: Copy) {
|
||||
dependsOn ':editor:assembleDev'
|
||||
from('editor/build/outputs/apk/dev')
|
||||
into(androidEditorBuildsDir)
|
||||
include('android_editor-dev.apk')
|
||||
}
|
||||
|
||||
task copyEditorDevAabToBin(type: Copy) {
|
||||
dependsOn ':editor:bundleDev'
|
||||
from('editor/build/outputs/bundle/dev')
|
||||
into(androidEditorBuildsDir)
|
||||
include('android_editor-dev.aab')
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the Godot Editor Android apk.
|
||||
*
|
||||
* Note: Unless the 'generateNativeLibs` argument is specified, the Godot 'tools' shared libraries
|
||||
* must have been generated (via scons) prior to running this gradle task.
|
||||
* The task will only build the apk(s) for which the shared libraries is available.
|
||||
*/
|
||||
task generateGodotEditor {
|
||||
gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
|
||||
dependsOn = generateBuildTasks("editor")
|
||||
}
|
||||
|
||||
/**
|
||||
* Master task used to coordinate the tasks defined above to generate the set of Godot templates.
|
||||
*/
|
||||
task generateGodotTemplates {
|
||||
gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
|
||||
dependsOn = generateBuildTasks("template")
|
||||
|
||||
finalizedBy 'zipGradleBuild'
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the same output as generateGodotTemplates but with dev symbols
|
||||
*/
|
||||
task generateDevTemplate {
|
||||
// add parameter to set symbols to true
|
||||
project.ext.doNotStrip = "true"
|
||||
|
||||
gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
|
||||
dependsOn = generateBuildTasks("template")
|
||||
|
||||
finalizedBy 'zipGradleBuild'
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
dependsOn 'cleanGodotEditor'
|
||||
dependsOn 'cleanGodotTemplates'
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the generated editor artifacts.
|
||||
*/
|
||||
task cleanGodotEditor(type: Delete) {
|
||||
// Delete the generated native tools libs
|
||||
delete("lib/libs/tools")
|
||||
|
||||
// Delete the library generated AAR files
|
||||
delete("lib/build/outputs/aar")
|
||||
|
||||
// Delete the generated binary apks
|
||||
delete("editor/build/outputs/apk")
|
||||
|
||||
// Delete the generated aab binaries
|
||||
delete("editor/build/outputs/bundle")
|
||||
|
||||
// Delete the Godot editor apks & aabs in the Godot bin directory
|
||||
delete(androidEditorBuildsDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the generated template artifacts.
|
||||
*/
|
||||
task cleanGodotTemplates(type: Delete) {
|
||||
// Delete the generated native libs
|
||||
delete("lib/libs")
|
||||
|
||||
// Delete the library generated AAR files
|
||||
delete("lib/build/outputs/aar")
|
||||
|
||||
// Delete the app libs directory contents
|
||||
delete("app/libs")
|
||||
|
||||
// Delete the generated binary apks
|
||||
delete("app/build/outputs/apk")
|
||||
|
||||
// Delete the Godot templates in the Godot bin directory
|
||||
delete("$binDir/android_debug.apk")
|
||||
delete("$binDir/android_dev.apk")
|
||||
delete("$binDir/android_release.apk")
|
||||
delete("$binDir/android_source.zip")
|
||||
delete("$binDir/godot-lib.template_debug.aar")
|
||||
delete("$binDir/godot-lib.template_debug.dev.aar")
|
||||
delete("$binDir/godot-lib.template_release.aar")
|
||||
|
||||
// Cover deletion for the libs using the previous naming scheme
|
||||
delete("$binDir/godot-lib.debug.aar")
|
||||
delete("$binDir/godot-lib.dev.aar")
|
||||
delete("$binDir/godot-lib.release.aar")
|
||||
}
|
||||
156
engine/platform/android/java/editor/build.gradle
Normal file
156
engine/platform/android/java/editor/build.gradle
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// Gradle build config for Godot Engine's Android port.
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'base'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
||||
implementation project(":lib")
|
||||
|
||||
implementation "androidx.window:window:1.3.0"
|
||||
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
}
|
||||
|
||||
ext {
|
||||
// Retrieve the build number from the environment variable; default to 0 if none is specified.
|
||||
// The build number is added as a suffix to the version code for upload to the Google Play store.
|
||||
getEditorBuildNumber = { ->
|
||||
int buildNumber = 0
|
||||
String versionStatus = System.getenv("GODOT_VERSION_STATUS")
|
||||
if (versionStatus != null && !versionStatus.isEmpty()) {
|
||||
try {
|
||||
buildNumber = Integer.parseInt(versionStatus.replaceAll("[^0-9]", ""))
|
||||
} catch (NumberFormatException ignored) {
|
||||
buildNumber = 0
|
||||
}
|
||||
}
|
||||
|
||||
return buildNumber
|
||||
}
|
||||
// Value by which the Godot version code should be offset by to make room for the build number
|
||||
editorBuildNumberOffset = 100
|
||||
|
||||
// Return the keystore file used for signing the release build.
|
||||
getGodotKeystoreFile = { ->
|
||||
def keyStore = System.getenv("GODOT_ANDROID_SIGN_KEYSTORE")
|
||||
if (keyStore == null) {
|
||||
return null
|
||||
}
|
||||
return file(keyStore)
|
||||
}
|
||||
|
||||
// Return the key alias used for signing the release build.
|
||||
getGodotKeyAlias = { ->
|
||||
def kAlias = System.getenv("GODOT_ANDROID_KEYSTORE_ALIAS")
|
||||
return kAlias
|
||||
}
|
||||
|
||||
// Return the password for the key used for signing the release build.
|
||||
getGodotSigningPassword = { ->
|
||||
def signingPassword = System.getenv("GODOT_ANDROID_SIGN_PASSWORD")
|
||||
return signingPassword
|
||||
}
|
||||
|
||||
// Returns true if the environment variables contains the configuration for signing the release
|
||||
// build.
|
||||
hasReleaseSigningConfigs = { ->
|
||||
def keystoreFile = getGodotKeystoreFile()
|
||||
def keyAlias = getGodotKeyAlias()
|
||||
def signingPassword = getGodotSigningPassword()
|
||||
|
||||
return keystoreFile != null && keystoreFile.isFile()
|
||||
&& keyAlias != null && !keyAlias.isEmpty()
|
||||
&& signingPassword != null && !signingPassword.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
def generateVersionCode() {
|
||||
int libraryVersionCode = getGodotLibraryVersionCode()
|
||||
return (libraryVersionCode * editorBuildNumberOffset) + getEditorBuildNumber()
|
||||
}
|
||||
|
||||
def generateVersionName() {
|
||||
String libraryVersionName = getGodotLibraryVersionName()
|
||||
int buildNumber = getEditorBuildNumber()
|
||||
return buildNumber == 0 ? libraryVersionName : libraryVersionName + ".$buildNumber"
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
buildToolsVersion versions.buildTools
|
||||
ndkVersion versions.ndkVersion
|
||||
|
||||
namespace = "org.godotengine.editor"
|
||||
|
||||
defaultConfig {
|
||||
// The 'applicationId' suffix allows to install Godot 3.x(v3) and 4.x(v4) on the same device
|
||||
applicationId "org.godotengine.editor.v4"
|
||||
versionCode generateVersionCode()
|
||||
versionName generateVersionName()
|
||||
minSdkVersion versions.minSdk
|
||||
targetSdkVersion versions.targetSdk
|
||||
|
||||
missingDimensionStrategy 'products', 'editor'
|
||||
manifestPlaceholders += [
|
||||
editorAppName: "Godot Editor 4",
|
||||
editorBuildSuffix: ""
|
||||
]
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName = "android_editor"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.javaVersion
|
||||
targetCompatibility versions.javaVersion
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = versions.javaVersion
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile getGodotKeystoreFile()
|
||||
storePassword getGodotSigningPassword()
|
||||
keyAlias getGodotKeyAlias()
|
||||
keyPassword getGodotSigningPassword()
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
dev {
|
||||
initWith debug
|
||||
applicationIdSuffix ".dev"
|
||||
manifestPlaceholders += [editorBuildSuffix: " (dev)"]
|
||||
}
|
||||
|
||||
debug {
|
||||
initWith release
|
||||
applicationIdSuffix ".debug"
|
||||
manifestPlaceholders += [editorBuildSuffix: " (debug)"]
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
||||
release {
|
||||
if (hasReleaseSigningConfigs()) {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
// 'doNotStrip' is enabled for development within Android Studio
|
||||
if (shouldNotStrip()) {
|
||||
doNotStrip '**/*.so'
|
||||
}
|
||||
}
|
||||
}
|
||||
1
engine/platform/android/java/editor/src/.gitignore
vendored
Normal file
1
engine/platform/android/java/editor/src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
!/debug
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto">
|
||||
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="false"
|
||||
android:xlargeScreens="true" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00030000"
|
||||
android:required="true" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/icon"
|
||||
android:label="${editorAppName}${editorBuildSuffix}"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:theme="@style/GodotEditorSplashScreenTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<profileable
|
||||
android:shell="true"
|
||||
android:enabled="true"
|
||||
tools:targetApi="29" />
|
||||
|
||||
<activity
|
||||
android:name=".GodotEditor"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="userLandscape">
|
||||
<layout
|
||||
android:defaultWidth="@dimen/editor_default_window_width"
|
||||
android:defaultHeight="@dimen/editor_default_window_height" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".GodotGame"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:exported="false"
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:launchMode="singleTask"
|
||||
android:process=":GodotGame"
|
||||
android:screenOrientation="userLandscape">
|
||||
<layout
|
||||
android:defaultWidth="@dimen/editor_default_window_width"
|
||||
android:defaultHeight="@dimen/editor_default_window_height" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**************************************************************************/
|
||||
/* EditorWindowInfo.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package org.godotengine.editor
|
||||
|
||||
/**
|
||||
* Specifies the policy for adjacent launches.
|
||||
*/
|
||||
enum class LaunchAdjacentPolicy {
|
||||
/**
|
||||
* Adjacent launches are disabled.
|
||||
*/
|
||||
DISABLED,
|
||||
|
||||
/**
|
||||
* Adjacent launches are enabled / disabled based on the device and screen metrics.
|
||||
*/
|
||||
AUTO,
|
||||
|
||||
/**
|
||||
* Adjacent launches are enabled.
|
||||
*/
|
||||
ENABLED
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the editor window to launch
|
||||
*/
|
||||
data class EditorWindowInfo(
|
||||
val windowClassName: String,
|
||||
val windowId: Int,
|
||||
val processNameSuffix: String,
|
||||
val launchAdjacentPolicy: LaunchAdjacentPolicy = LaunchAdjacentPolicy.DISABLED
|
||||
) {
|
||||
constructor(
|
||||
windowClass: Class<*>,
|
||||
windowId: Int,
|
||||
processNameSuffix: String,
|
||||
launchAdjacentPolicy: LaunchAdjacentPolicy = LaunchAdjacentPolicy.DISABLED
|
||||
) : this(windowClass.name, windowId, processNameSuffix, launchAdjacentPolicy)
|
||||
}
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
/**************************************************************************/
|
||||
/* GodotEditor.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package org.godotengine.editor
|
||||
|
||||
import android.Manifest
|
||||
import android.app.ActivityManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.window.layout.WindowMetricsCalculator
|
||||
import org.godotengine.godot.GodotActivity
|
||||
import org.godotengine.godot.GodotLib
|
||||
import org.godotengine.godot.utils.PermissionsUtil
|
||||
import org.godotengine.godot.utils.ProcessPhoenix
|
||||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Base class for the Godot Android Editor activities.
|
||||
*
|
||||
* This provides the basic templates for the activities making up this application.
|
||||
* Each derived activity runs in its own process, which enable up to have several instances of
|
||||
* the Godot engine up and running at the same time.
|
||||
*
|
||||
* It also plays the role of the primary editor window.
|
||||
*/
|
||||
open class GodotEditor : GodotActivity() {
|
||||
|
||||
companion object {
|
||||
private val TAG = GodotEditor::class.java.simpleName
|
||||
|
||||
private const val WAIT_FOR_DEBUGGER = false
|
||||
|
||||
private const val EXTRA_COMMAND_LINE_PARAMS = "command_line_params"
|
||||
|
||||
// Command line arguments
|
||||
private const val EDITOR_ARG = "--editor"
|
||||
private const val EDITOR_ARG_SHORT = "-e"
|
||||
private const val EDITOR_PROJECT_MANAGER_ARG = "--project-manager"
|
||||
private const val EDITOR_PROJECT_MANAGER_ARG_SHORT = "-p"
|
||||
|
||||
// Info for the various classes used by the editor
|
||||
internal val EDITOR_MAIN_INFO = EditorWindowInfo(GodotEditor::class.java, 777, "")
|
||||
internal val RUN_GAME_INFO = EditorWindowInfo(GodotGame::class.java, 667, ":GodotGame", LaunchAdjacentPolicy.AUTO)
|
||||
|
||||
/**
|
||||
* Sets of constants to specify the window to use to run the project.
|
||||
*
|
||||
* Should match the values in 'editor/editor_settings.cpp' for the
|
||||
* 'run/window_placement/android_window' setting.
|
||||
*/
|
||||
private const val ANDROID_WINDOW_AUTO = 0
|
||||
private const val ANDROID_WINDOW_SAME_AS_EDITOR = 1
|
||||
private const val ANDROID_WINDOW_SIDE_BY_SIDE_WITH_EDITOR = 2
|
||||
}
|
||||
|
||||
private val commandLineParams = ArrayList<String>()
|
||||
private val editorLoadingIndicator: View? by lazy { findViewById(R.id.editor_loading_indicator) }
|
||||
|
||||
override fun getGodotAppLayout() = R.layout.godot_editor_layout
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen()
|
||||
|
||||
// We exclude certain permissions from the set we request at startup, as they'll be
|
||||
// requested on demand based on use-cases.
|
||||
PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO))
|
||||
|
||||
val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||
Log.d(TAG, "Starting intent $intent with parameters ${params.contentToString()}")
|
||||
updateCommandLineParams(params?.asList() ?: emptyList())
|
||||
|
||||
if (BuildConfig.BUILD_TYPE == "dev" && WAIT_FOR_DEBUGGER) {
|
||||
Debug.waitForDebugger()
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onGodotSetupCompleted() {
|
||||
super.onGodotSetupCompleted()
|
||||
val longPressEnabled = enableLongPressGestures()
|
||||
val panScaleEnabled = enablePanAndScaleGestures()
|
||||
|
||||
checkForProjectPermissionsToEnable()
|
||||
|
||||
runOnUiThread {
|
||||
// Enable long press, panning and scaling gestures
|
||||
godotFragment?.godot?.renderView?.inputHandler?.apply {
|
||||
enableLongPress(longPressEnabled)
|
||||
enablePanningAndScalingGestures(panScaleEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGodotMainLoopStarted() {
|
||||
super.onGodotMainLoopStarted()
|
||||
runOnUiThread {
|
||||
// Hide the loading indicator
|
||||
editorLoadingIndicator?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for project permissions to enable
|
||||
*/
|
||||
protected open fun checkForProjectPermissionsToEnable() {
|
||||
// Check for RECORD_AUDIO permission
|
||||
val audioInputEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("audio/driver/enable_input"))
|
||||
if (audioInputEnabled) {
|
||||
PermissionsUtil.requestPermission(Manifest.permission.RECORD_AUDIO, this)
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected open fun updateCommandLineParams(args: List<String>) {
|
||||
// Update the list of command line params with the new args
|
||||
commandLineParams.clear()
|
||||
if (args.isNotEmpty()) {
|
||||
commandLineParams.addAll(args)
|
||||
}
|
||||
if (BuildConfig.BUILD_TYPE == "dev") {
|
||||
commandLineParams.add("--benchmark")
|
||||
}
|
||||
}
|
||||
|
||||
final override fun getCommandLine() = commandLineParams
|
||||
|
||||
protected open fun getEditorWindowInfo(args: Array<String>): EditorWindowInfo {
|
||||
var hasEditor = false
|
||||
|
||||
var i = 0
|
||||
while (i < args.size) {
|
||||
when (args[i++]) {
|
||||
EDITOR_ARG, EDITOR_ARG_SHORT, EDITOR_PROJECT_MANAGER_ARG, EDITOR_PROJECT_MANAGER_ARG_SHORT -> hasEditor = true
|
||||
}
|
||||
}
|
||||
|
||||
return if (hasEditor) {
|
||||
EDITOR_MAIN_INFO
|
||||
} else {
|
||||
RUN_GAME_INFO
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun getEditorWindowInfoForInstanceId(instanceId: Int): EditorWindowInfo? {
|
||||
return when (instanceId) {
|
||||
RUN_GAME_INFO.windowId -> RUN_GAME_INFO
|
||||
EDITOR_MAIN_INFO.windowId -> EDITOR_MAIN_INFO
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewGodotInstanceRequested(args: Array<String>): Int {
|
||||
val editorWindowInfo = getEditorWindowInfo(args)
|
||||
|
||||
// Launch a new activity
|
||||
val newInstance = Intent()
|
||||
.setComponent(ComponentName(this, editorWindowInfo.windowClassName))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_COMMAND_LINE_PARAMS, args)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (editorWindowInfo.launchAdjacentPolicy == LaunchAdjacentPolicy.ENABLED ||
|
||||
(editorWindowInfo.launchAdjacentPolicy == LaunchAdjacentPolicy.AUTO && shouldGameLaunchAdjacent())) {
|
||||
Log.v(TAG, "Adding flag for adjacent launch")
|
||||
newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
|
||||
}
|
||||
}
|
||||
if (editorWindowInfo.windowClassName == javaClass.name) {
|
||||
Log.d(TAG, "Restarting ${editorWindowInfo.windowClassName} with parameters ${args.contentToString()}")
|
||||
val godot = godot
|
||||
if (godot != null) {
|
||||
godot.destroyAndKillProcess {
|
||||
ProcessPhoenix.triggerRebirth(this, newInstance)
|
||||
}
|
||||
} else {
|
||||
ProcessPhoenix.triggerRebirth(this, newInstance)
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Starting ${editorWindowInfo.windowClassName} with parameters ${args.contentToString()}")
|
||||
newInstance.putExtra(EXTRA_NEW_LAUNCH, true)
|
||||
startActivity(newInstance)
|
||||
}
|
||||
return editorWindowInfo.windowId
|
||||
}
|
||||
|
||||
final override fun onGodotForceQuit(godotInstanceId: Int): Boolean {
|
||||
val editorWindowInfo = getEditorWindowInfoForInstanceId(godotInstanceId) ?: return super.onGodotForceQuit(godotInstanceId)
|
||||
|
||||
if (editorWindowInfo.windowClassName == javaClass.name) {
|
||||
Log.d(TAG, "Force quitting ${editorWindowInfo.windowClassName}")
|
||||
ProcessPhoenix.forceQuit(this)
|
||||
return true
|
||||
}
|
||||
|
||||
val processName = packageName + editorWindowInfo.processNameSuffix
|
||||
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
val runningProcesses = activityManager.runningAppProcesses
|
||||
for (runningProcess in runningProcesses) {
|
||||
if (runningProcess.processName == processName) {
|
||||
// Killing process directly
|
||||
Log.v(TAG, "Killing Godot process ${runningProcess.processName}")
|
||||
Process.killProcess(runningProcess.pid)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return super.onGodotForceQuit(godotInstanceId)
|
||||
}
|
||||
|
||||
// Get the screen's density scale
|
||||
private val isLargeScreen: Boolean
|
||||
// Get the minimum window size // Correspond to the EXPANDED window size class.
|
||||
get() {
|
||||
val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
|
||||
|
||||
// Get the screen's density scale
|
||||
val scale = resources.displayMetrics.density
|
||||
|
||||
// Get the minimum window size
|
||||
val minSize = min(metrics.bounds.width(), metrics.bounds.height()).toFloat()
|
||||
val minSizeDp = minSize / scale
|
||||
return minSizeDp >= 840f // Correspond to the EXPANDED window size class.
|
||||
}
|
||||
|
||||
override fun setRequestedOrientation(requestedOrientation: Int) {
|
||||
if (!overrideOrientationRequest()) {
|
||||
super.setRequestedOrientation(requestedOrientation)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Godot Android Editor sets its own orientation via its AndroidManifest
|
||||
*/
|
||||
protected open fun overrideOrientationRequest() = true
|
||||
|
||||
/**
|
||||
* Enable long press gestures for the Godot Android editor.
|
||||
*/
|
||||
protected open fun enableLongPressGestures() =
|
||||
java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_long_press_as_right_click"))
|
||||
|
||||
/**
|
||||
* Enable pan and scale gestures for the Godot Android editor.
|
||||
*/
|
||||
protected open fun enablePanAndScaleGestures() =
|
||||
java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_pan_and_scale_gestures"))
|
||||
|
||||
/**
|
||||
* Whether we should launch the new godot instance in an adjacent window
|
||||
* @see https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_LAUNCH_ADJACENT
|
||||
*/
|
||||
private fun shouldGameLaunchAdjacent(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
try {
|
||||
when (Integer.parseInt(GodotLib.getEditorSetting("run/window_placement/android_window"))) {
|
||||
ANDROID_WINDOW_SAME_AS_EDITOR -> false
|
||||
ANDROID_WINDOW_SIDE_BY_SIDE_WITH_EDITOR -> true
|
||||
else -> {
|
||||
// ANDROID_WINDOW_AUTO
|
||||
isInMultiWindowMode || isLargeScreen
|
||||
}
|
||||
}
|
||||
} catch (e: NumberFormatException) {
|
||||
// Fall-back to the 'Auto' behavior
|
||||
isInMultiWindowMode || isLargeScreen
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
// Check if we got the MANAGE_EXTERNAL_STORAGE permission
|
||||
if (requestCode == PermissionsUtil.REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
if (!Environment.isExternalStorageManager()) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
R.string.denied_storage_permission_error_msg,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// Check if we got access to the necessary storage permissions
|
||||
if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
var hasReadAccess = false
|
||||
var hasWriteAccess = false
|
||||
for (i in permissions.indices) {
|
||||
if (Manifest.permission.READ_EXTERNAL_STORAGE == permissions[i] && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
hasReadAccess = true
|
||||
}
|
||||
if (Manifest.permission.WRITE_EXTERNAL_STORAGE == permissions[i] && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
hasWriteAccess = true
|
||||
}
|
||||
}
|
||||
if (!hasReadAccess || !hasWriteAccess) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
R.string.denied_storage_permission_error_msg,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/**************************************************************************/
|
||||
/* GodotGame.kt */
|
||||
/**************************************************************************/
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package org.godotengine.editor
|
||||
|
||||
import org.godotengine.godot.GodotLib
|
||||
|
||||
/**
|
||||
* Drives the 'run project' window of the Godot Editor.
|
||||
*/
|
||||
class GodotGame : GodotEditor() {
|
||||
|
||||
override fun getGodotAppLayout() = org.godotengine.godot.R.layout.godot_app_layout
|
||||
|
||||
override fun overrideOrientationRequest() = false
|
||||
|
||||
override fun enableLongPressGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
|
||||
|
||||
override fun enablePanAndScaleGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
|
||||
|
||||
override fun checkForProjectPermissionsToEnable() {
|
||||
// Nothing to do.. by the time we get here, the project permissions will have already
|
||||
// been requested by the Editor window.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/godot_fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ProgressBar
|
||||
style="@android:style/Widget.Holo.ProgressBar.Large"
|
||||
android:id="@+id/editor_loading_indicator"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.80"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="editor_default_window_height">600dp</dimen>
|
||||
<dimen name="editor_default_window_width">1024dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="denied_storage_permission_error_msg">Missing storage access permission!</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="GodotEditorTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen">
|
||||
</style>
|
||||
|
||||
<style name="GodotEditorSplashScreenTheme" parent="Theme.SplashScreen.IconBackground">
|
||||
<!-- Set the theme of the Activity that directly follows your splash
|
||||
screen. This is required. -->
|
||||
<item name="postSplashScreenTheme">@style/GodotEditorTheme</item>
|
||||
</style>
|
||||
</resources>
|
||||
31
engine/platform/android/java/gradle.properties
Normal file
31
engine/platform/android/java/gradle.properties
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Project-wide Gradle settings.
|
||||
# NOTE: This should be kept in sync with 'godot/platform/android/java/app/gradle.properties' except
|
||||
# where otherwise specified.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# https://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx4536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# https://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
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
|
||||
BIN
engine/platform/android/java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
engine/platform/android/java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
engine/platform/android/java/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
engine/platform/android/java/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#Wed Jan 17 12:08:26 PST 2024
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
185
engine/platform/android/java/gradlew
vendored
Executable file
185
engine/platform/android/java/gradlew
vendored
Executable file
|
|
@ -0,0 +1,185 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
engine/platform/android/java/gradlew.bat
vendored
Normal file
89
engine/platform/android/java/gradlew.bat
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
34
engine/platform/android/java/lib/AndroidManifest.xml
Normal file
34
engine/platform/android/java/lib/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<application>
|
||||
|
||||
<!-- Records the version of the Godot library -->
|
||||
<meta-data
|
||||
android:name="org.godotengine.library.version"
|
||||
android:value="${godotLibraryVersion}" />
|
||||
|
||||
<service android:name=".GodotDownloaderService" />
|
||||
|
||||
<activity
|
||||
android:name=".utils.ProcessPhoenix"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:process=":phoenix"
|
||||
android:exported="false"
|
||||
/>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/godot_provider_paths" />
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue