summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/SCsub108
-rw-r--r--platform/android/export/export.cpp403
-rw-r--r--platform/android/file_access_android.h2
-rw-r--r--platform/android/file_access_jandroid.h2
-rw-r--r--platform/android/java/AndroidManifest.xml (renamed from platform/android/AndroidManifest.xml.template)19
-rw-r--r--platform/android/java/build.gradle (renamed from platform/android/build.gradle.template)59
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java9
-rw-r--r--platform/osx/export/export.cpp2
-rw-r--r--platform/windows/detect.py6
-rw-r--r--platform/windows/os_windows.cpp35
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--platform/x11/detect.py10
-rw-r--r--platform/x11/os_x11.cpp38
13 files changed, 503 insertions, 192 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index d494372bcd..22ed476c6f 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -34,114 +34,6 @@ env_thirdparty = env_android.Clone()
env_thirdparty.disable_warnings()
android_objects.append(env_thirdparty.SharedObject('#thirdparty/misc/ifaddrs-android.cc'))
-abspath = env.Dir(".").abspath
-
-with open_utf8(abspath + "/build.gradle.template", "r") as gradle_basein:
- gradle_text = gradle_basein.read()
-
-gradle_maven_flat_text = ""
-if len(env.android_flat_dirs) > 0:
- gradle_maven_flat_text += "flatDir {\n"
- gradle_maven_flat_text += "\tdirs "
- for x in env.android_flat_dirs:
- gradle_maven_flat_text += "'" + x + "',"
-
- gradle_maven_flat_text = gradle_maven_flat_text[:-1]
- gradle_maven_flat_text += "\n\t}\n"
-
-gradle_maven_repos_text = ""
-gradle_maven_repos_text += gradle_maven_flat_text
-
-if len(env.android_maven_repos) > 0:
- gradle_maven_repos_text += ""
- for x in env.android_maven_repos:
- gradle_maven_repos_text += "\tmaven {\n"
- gradle_maven_repos_text += "\t" + x + "\n"
- gradle_maven_repos_text += "\t}\n"
-
-gradle_maven_dependencies_text = ""
-
-for x in env.android_dependencies:
- gradle_maven_dependencies_text += x + "\n\t"
-
-gradle_java_dirs_text = ""
-
-for x in env.android_java_dirs:
- gradle_java_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_plugins = ""
-for x in env.android_gradle_plugins:
- gradle_plugins += "apply plugin: \"" + x + "\"\n"
-
-gradle_classpath = ""
-for x in env.android_gradle_classpath:
- gradle_classpath += "\t\tclasspath \"" + x + "\"\n"
-
-gradle_res_dirs_text = ""
-
-for x in env.android_res_dirs:
- gradle_res_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_aidl_dirs_text = ""
-
-for x in env.android_aidl_dirs:
- gradle_aidl_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_jni_dirs_text = ""
-
-for x in env.android_jni_dirs:
- gradle_jni_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_asset_dirs_text = ""
-
-for x in env.android_asset_dirs:
- gradle_asset_dirs_text += ",'" + x.replace("\\", "/") + "'"
-
-gradle_default_config_text = ""
-
-minSdk = 18
-targetSdk = 28
-
-for x in env.android_default_config:
- if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk:
- x = "minSdkVersion " + str(minSdk)
- if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk:
- x = "targetSdkVersion " + str(targetSdk)
-
- gradle_default_config_text += x + "\n\t\t"
-
-if "minSdkVersion" not in gradle_default_config_text:
- gradle_default_config_text += ("minSdkVersion " + str(minSdk) + "\n\t\t")
-
-if "targetSdkVersion" not in gradle_default_config_text:
- gradle_default_config_text += ("targetSdkVersion " + str(targetSdk) + "\n\t\t")
-
-gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$", gradle_maven_repos_text)
-gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$", gradle_maven_dependencies_text)
-gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$", gradle_java_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$", gradle_res_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$", gradle_asset_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$", gradle_aidl_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$", gradle_jni_dirs_text)
-gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$", gradle_default_config_text)
-gradle_text = gradle_text.replace("$$GRADLE_PLUGINS$$", gradle_plugins)
-gradle_text = gradle_text.replace("$$GRADLE_CLASSPATH$$", gradle_classpath)
-
-with open_utf8(abspath + "/java/build.gradle", "w") as gradle_baseout:
- gradle_baseout.write(gradle_text)
-
-
-with open_utf8(abspath + "/AndroidManifest.xml.template", "r") as pp_basein:
- manifest = pp_basein.read()
-
-manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$", env.android_manifest_chunk)
-manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$", env.android_permission_chunk)
-manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$", env.android_appattributes_chunk)
-
-with open_utf8(abspath + "/java/AndroidManifest.xml", "w") as pp_baseout:
- pp_baseout.write(manifest)
-
-
lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
lib_arch_dir = ''
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index e489bce3f8..f70cee2964 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -417,6 +417,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
name = "noname";
pname = pname.replace("$genname", name);
+
return pname;
}
@@ -1143,11 +1144,12 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_package/use_custom_build"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.$genname"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0));
@@ -1388,21 +1390,25 @@ public:
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
- r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String();
- if (p_preset->get("custom_package/debug") != "") {
- if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
- r_missing_templates = false;
- } else {
- err += TTR("Custom debug template not found.") + "\n";
+ if (!bool(p_preset->get("custom_package/use_custom_build"))) {
+
+ r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String();
+
+ if (p_preset->get("custom_package/debug") != "") {
+ if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
+ r_missing_templates = false;
+ } else {
+ err += TTR("Custom debug template not found.") + "\n";
+ }
}
- }
- if (p_preset->get("custom_package/release") != "") {
- if (FileAccess::exists(p_preset->get("custom_package/release"))) {
- r_missing_templates = false;
- } else {
- err += TTR("Custom release template not found.") + "\n";
+ if (p_preset->get("custom_package/release") != "") {
+ if (FileAccess::exists(p_preset->get("custom_package/release"))) {
+ r_missing_templates = false;
+ } else {
+ err += TTR("Custom release template not found.") + "\n";
+ }
}
}
@@ -1435,6 +1441,30 @@ public:
}
}
+ if (bool(p_preset->get("custom_package/use_custom_build"))) {
+ String sdk_path = EditorSettings::get_singleton()->get("export/android/custom_build_sdk_path");
+ if (sdk_path == "") {
+ err += TTR("Custom build requires a valid Android SDK path in Editor Settings.") + "\n";
+ valid = false;
+ } else {
+ Error errn;
+ DirAccess *da = DirAccess::open(sdk_path.plus_file("tools"), &errn);
+ if (errn != OK) {
+ err += TTR("Invalid Android SDK path for custom build in Editor Settings.") + "\n";
+ valid = false;
+ }
+ if (da) {
+ memdelete(da);
+ }
+ }
+
+ if (!FileAccess::exists("res://android/build/build.gradle")) {
+
+ err += TTR("Android project is not installed for compiling. Install from Editor menu.") + "\n";
+ valid = false;
+ }
+ }
+
bool apk_expansion = p_preset->get("apk_expansion/enable");
if (apk_expansion) {
@@ -1473,6 +1503,260 @@ public:
return list;
}
+ void _update_custom_build_project() {
+
+ DirAccessRef da = DirAccess::open("res://android");
+
+ ERR_FAIL_COND(!da);
+ Map<String, List<String> > directory_paths;
+ Map<String, List<String> > manifest_sections;
+ Map<String, List<String> > gradle_sections;
+ da->list_dir_begin();
+ String d = da->get_next();
+ while (d != String()) {
+
+ if (!d.begins_with(".") && d != "build" && da->current_is_dir()) { //a dir and not the build dir
+ //add directories found
+ DirAccessRef ds = DirAccess::open(String("res://android").plus_file(d));
+ if (ds) {
+ ds->list_dir_begin();
+ String sd = ds->get_next();
+ while (sd != String()) {
+
+ if (!sd.begins_with(".") && ds->current_is_dir()) {
+ String key = sd.to_upper();
+ if (!directory_paths.has(key)) {
+ directory_paths[key] = List<String>();
+ }
+ String path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android").plus_file(d).plus_file(sd);
+ directory_paths[key].push_back(path);
+ print_line("Add: " + sd + ":" + path);
+ }
+
+ sd = ds->get_next();
+ }
+ ds->list_dir_end();
+ }
+ //parse manifest
+ {
+ FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("AndroidManifest.conf"), FileAccess::READ);
+ if (f) {
+
+ String section;
+ while (!f->eof_reached()) {
+ String l = f->get_line();
+ String k = l.strip_edges();
+ if (k.begins_with("[")) {
+ section = k.substr(1, k.length() - 2).strip_edges().to_upper();
+ print_line("Section: " + section);
+ } else if (k != String()) {
+ if (!manifest_sections.has(section)) {
+ manifest_sections[section] = List<String>();
+ }
+ manifest_sections[section].push_back(l);
+ }
+ }
+
+ f->close();
+ }
+ }
+ //parse gradle
+ {
+ FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("gradle.conf"), FileAccess::READ);
+ if (f) {
+
+ String section;
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+ String k = l.strip_edges();
+ if (k.begins_with("[")) {
+ section = k.substr(1, k.length() - 2).strip_edges().to_upper();
+ print_line("Section: " + section);
+ } else if (k != String()) {
+ if (!gradle_sections.has(section)) {
+ gradle_sections[section] = List<String>();
+ }
+ gradle_sections[section].push_back(l);
+ }
+ }
+ }
+ }
+ }
+ d = da->get_next();
+ }
+ da->list_dir_end();
+
+ { //fix gradle build
+
+ String new_file;
+ {
+ FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::READ);
+ if (f) {
+
+ while (!f->eof_reached()) {
+ String l = f->get_line();
+
+ if (l.begins_with("//CHUNK_")) {
+ String text = l.replace_first("//CHUNK_", "");
+ int begin_pos = text.find("_BEGIN");
+ if (begin_pos != -1) {
+ text = text.substr(0, begin_pos);
+ text = text.to_upper(); //just in case
+
+ String end_marker = "//CHUNK_" + text + "_END";
+ size_t pos = f->get_position();
+ bool found = false;
+ while (!f->eof_reached()) {
+ l = f->get_line();
+ if (l.begins_with(end_marker)) {
+ found = true;
+ break;
+ }
+ }
+
+ new_file += "//CHUNK_" + text + "_BEGIN\n";
+
+ if (!found) {
+ ERR_PRINTS("No end marker found in build.gradle for chunk: " + text);
+ f->seek(pos);
+ } else {
+
+ //add chunk lines
+ if (gradle_sections.has(text)) {
+ for (List<String>::Element *E = gradle_sections[text].front(); E; E = E->next()) {
+ new_file += E->get() + "\n";
+ }
+ }
+ new_file += end_marker + "\n";
+ }
+ } else {
+ new_file += l + "\n"; //pass line by
+ }
+ } else if (l.begins_with("//DIR_")) {
+ String text = l.replace_first("//DIR_", "");
+ int begin_pos = text.find("_BEGIN");
+ if (begin_pos != -1) {
+ text = text.substr(0, begin_pos);
+ text = text.to_upper(); //just in case
+
+ String end_marker = "//DIR_" + text + "_END";
+ size_t pos = f->get_position();
+ bool found = false;
+ while (!f->eof_reached()) {
+ l = f->get_line();
+ if (l.begins_with(end_marker)) {
+ found = true;
+ break;
+ }
+ }
+
+ new_file += "//DIR_" + text + "_BEGIN\n";
+
+ if (!found) {
+ ERR_PRINTS("No end marker found in build.gradle for dir: " + text);
+ f->seek(pos);
+ } else {
+ //add chunk lines
+ if (directory_paths.has(text)) {
+ for (List<String>::Element *E = directory_paths[text].front(); E; E = E->next()) {
+ new_file += ",'" + E->get().replace("'", "\'") + "'";
+ new_file += "\n";
+ }
+ }
+ new_file += end_marker + "\n";
+ }
+ } else {
+ new_file += l + "\n"; //pass line by
+ }
+
+ } else {
+ new_file += l + "\n";
+ }
+ }
+ }
+ }
+
+ FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::WRITE);
+ f->store_string(new_file);
+ f->close();
+ }
+
+ { //fix manifest
+
+ String new_file;
+ {
+ FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::READ);
+ if (f) {
+
+ while (!f->eof_reached()) {
+ String l = f->get_line();
+
+ if (l.begins_with("<!--CHUNK_")) {
+ String text = l.replace_first("<!--CHUNK_", "");
+ int begin_pos = text.find("_BEGIN-->");
+ if (begin_pos != -1) {
+ text = text.substr(0, begin_pos);
+ text = text.to_upper(); //just in case
+
+ String end_marker = "<!--CHUNK_" + text + "_END-->";
+ size_t pos = f->get_position();
+ bool found = false;
+ while (!f->eof_reached()) {
+ l = f->get_line();
+ if (l.begins_with(end_marker)) {
+ found = true;
+ break;
+ }
+ }
+
+ new_file += "<!--CHUNK_" + text + "_BEGIN-->\n";
+
+ if (!found) {
+ ERR_PRINTS("No end marker found in AndroidManifest.conf for chunk: " + text);
+ f->seek(pos);
+ } else {
+ //add chunk lines
+ if (manifest_sections.has(text)) {
+ for (List<String>::Element *E = manifest_sections[text].front(); E; E = E->next()) {
+ new_file += E->get() + "\n";
+ }
+ }
+ new_file += end_marker + "\n";
+ }
+ } else {
+ new_file += l + "\n"; //pass line by
+ }
+
+ } else if (l.strip_edges().begins_with("<application")) {
+ String last_tag = "android:icon=\"@drawable/icon\"";
+ int last_tag_pos = l.find(last_tag);
+ if (last_tag_pos == -1) {
+ WARN_PRINTS("No adding of application tags because could not find last tag for <application: " + last_tag);
+ new_file += l + "\n";
+ } else {
+ String base = l.substr(0, last_tag_pos + last_tag.length());
+ if (manifest_sections.has("application_tags")) {
+ for (List<String>::Element *E = manifest_sections["application_tags"].front(); E; E = E->next()) {
+ String to_add = E->get().strip_edges();
+ base += " " + to_add + " ";
+ }
+ }
+ base += ">\n";
+ new_file += base;
+ }
+ } else {
+ new_file += l + "\n";
+ }
+ }
+ }
+ }
+
+ FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::WRITE);
+ f->store_string(new_file);
+ f->close();
+ }
+ }
+
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -1481,21 +1765,86 @@ public:
EditorProgress ep("export", "Exporting for Android", 105);
- if (p_debug)
- src_apk = p_preset->get("custom_package/debug");
- else
- src_apk = p_preset->get("custom_package/release");
+ if (bool(p_preset->get("custom_package/use_custom_build"))) { //custom build
+ //re-generate build.gradle and AndroidManifest.xml
- src_apk = src_apk.strip_edges();
- if (src_apk == "") {
+ { //test that installed build version is alright
+ FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
+ return ERR_UNCONFIGURED;
+ }
+ String version = f->get_line().strip_edges();
+ if (version != VERSION_FULL_CONFIG) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
+ return ERR_UNCONFIGURED;
+ }
+ }
+ //build project if custom build is enabled
+ String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path");
+
+ ERR_FAIL_COND_V(sdk_path == "", ERR_UNCONFIGURED);
+
+ _update_custom_build_project();
+
+ OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
+
+ String build_command;
+#ifdef WINDOWS_ENABLED
+ build_command = "gradlew.bat";
+#else
+ build_command = "gradlew";
+#endif
+
+ String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
+
+ build_command = build_path.plus_file(build_command);
+
+ List<String> cmdline;
+ cmdline.push_back("build");
+ cmdline.push_back("-p");
+ cmdline.push_back(build_path);
+ /*{ used for debug
+ int ec;
+ String pipe;
+ OS::get_singleton()->execute(build_command, cmdline, true, NULL, NULL, &ec);
+ print_line("exit code: " + itos(ec));
+ }
+ */
+ int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
+ if (result != 0) {
+ EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation."));
+ return ERR_CANT_CREATE;
+ }
if (p_debug) {
- src_apk = find_export_template("android_debug.apk");
+ src_apk = build_path.plus_file("build/outputs/apk/debug/build-debug-unsigned.apk");
} else {
- src_apk = find_export_template("android_release.apk");
+ src_apk = build_path.plus_file("build/outputs/apk/release/build-release-unsigned.apk");
}
+
+ if (!FileAccess::exists(src_apk)) {
+ EditorNode::get_singleton()->show_warning(TTR("No build apk generated at: ") + "\n" + src_apk);
+ return ERR_CANT_CREATE;
+ }
+
+ } else {
+
+ if (p_debug)
+ src_apk = p_preset->get("custom_package/debug");
+ else
+ src_apk = p_preset->get("custom_package/release");
+
+ src_apk = src_apk.strip_edges();
if (src_apk == "") {
- EditorNode::add_io_error("Package not found: " + src_apk);
- return ERR_FILE_NOT_FOUND;
+ if (p_debug) {
+ src_apk = find_export_template("android_debug.apk");
+ } else {
+ src_apk = find_export_template("android_release.apk");
+ }
+ if (src_apk == "") {
+ EditorNode::add_io_error("Package not found: " + src_apk);
+ return ERR_FILE_NOT_FOUND;
+ }
}
}
@@ -1923,10 +2272,6 @@ public:
zipClose(final_apk, NULL);
unzClose(tmp_unaligned);
- if (err) {
- return err;
- }
-
return OK;
}
@@ -1979,6 +2324,8 @@ void register_android_exporter() {
EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey");
EDITOR_DEF("export/android/debug_keystore_pass", "android");
EDITOR_DEF("export/android/force_system_user", false);
+ EDITOR_DEF("export/android/custom_build_sdk_path", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR, "*.keystore"));
EDITOR_DEF("export/android/timestamping_authority_url", "");
EDITOR_DEF("export/android/shutdown_adb_on_exit", true);
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index f8d46ea5d2..b8e78627ec 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -70,6 +70,8 @@ public:
virtual bool file_exists(const String &p_path); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
//static void make_default();
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
index 4f02fea81d..9429100d65 100644
--- a/platform/android/file_access_jandroid.h
+++ b/platform/android/file_access_jandroid.h
@@ -74,6 +74,8 @@ public:
static void setup(jobject p_io);
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
FileAccessJAndroid();
~FileAccessJAndroid();
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/java/AndroidManifest.xml
index daaf847f11..613d24fbd2 100644
--- a/platform/android/AndroidManifest.xml.template
+++ b/platform/android/java/AndroidManifest.xml
@@ -11,11 +11,20 @@
android:largeScreens="true"
android:xlargeScreens="true"/>
+<!--glEsVersion is modified by the exporter, changing this value here has no effect-->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
+<!--Adding custom text to manifest is fine, but do it outside the custom user and application BEGIN/ENDregions, as that gets rewritten-->
-$$ADD_PERMISSION_CHUNKS$$
+<!--Custom permissions XML added by add-ons. It's recommended to add them from the export preset, though-->
+<!--CHUNK_USER_PERMISSIONS_BEGIN-->
+<!--CHUNK_USER_PERMISSIONS_END-->
+
+<!--Anything in this line after the icon will be erased when doing custom build. If you want to add tags manually, do before it.-->
+ <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:icon="@drawable/icon">
+
+<!--The following values are replaced when Godot exports, modifying them here has no effect. Do theses changes in the-->
+<!--export preset. Adding new ones is fine.-->
- <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" $$ADD_APPATTRIBUTE_CHUNKS$$ >
<activity android:name="org.godotengine.godot.Godot"
android:label="@string/godot_project_name_string"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -32,13 +41,15 @@ $$ADD_PERMISSION_CHUNKS$$
</activity>
<service android:name="org.godotengine.godot.GodotDownloaderService" />
-$$ADD_APPLICATION_CHUNKS$$
+<!--Custom application XML added by add-ons-->
+<!--CHUNK_APPLICATION_BEGIN-->
+<!--CHUNK_APPLICATION_END-->
</application>
<instrumentation android:icon="@drawable/icon"
android:label="@string/godot_project_name_string"
android:name="org.godotengine.godot.GodotInstrumentation"
- android:targetPackage="com.godot.game" />
+ android:targetPackage="org.godotengine.game" />
</manifest>
diff --git a/platform/android/build.gradle.template b/platform/android/java/build.gradle
index 2fea250061..c468277daa 100644
--- a/platform/android/build.gradle.template
+++ b/platform/android/java/build.gradle
@@ -1,12 +1,17 @@
+//Gradle project for Godot Engine Android port.
+//Do not modify code between the BEGIN/END sections, as it's autogenerated by add-ons
+
buildscript {
repositories {
google()
jcenter()
- $$GRADLE_REPOSITORY_URLS$$
+//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN
+//CHUNK_BUILDSCRIPT_REPOSITORIES_END
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
- $$GRADLE_CLASSPATH$$
+//CHUNK_BUILDSCRIPT_DEPENDENCIES_BEGIN
+//CHUNK_BUILDSCRIPT_DEPENDENCIES_END
}
}
@@ -17,13 +22,16 @@ allprojects {
mavenCentral()
google()
jcenter()
- $$GRADLE_REPOSITORY_URLS$$
+//CHUNK_ALLPROJECTS_REPOSITORIES_BEGIN
+//CHUNK_ALLPROJECTS_REPOSITORIES_END
+
}
}
dependencies {
implementation "com.android.support:support-core-utils:28.0.0"
- $$GRADLE_DEPENDENCIES$$
+//CHUNK_DEPENDENCIES_BEGIN
+//CHUNK_DEPENDENCIES_END
}
android {
@@ -42,7 +50,10 @@ android {
exclude 'META-INF/NOTICE'
}
defaultConfig {
- $$GRADLE_DEFAULT_CONFIG$$
+ minSdkVersion 18
+ targetSdkVersion 28
+//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN
+//CHUNK_ANDROID_DEFAULTCONFIG_END
}
// Both signing and zip-aligning will be done at export time
buildTypes.all { buildType ->
@@ -53,36 +64,50 @@ android {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src'
- $$GRADLE_JAVA_DIRS$$
+//DIR_SRC_BEGIN
+//DIR_SRC_END
]
res.srcDirs = [
'res'
- $$GRADLE_RES_DIRS$$
+//DIR_RES_BEGIN
+//DIR_RES_END
]
aidl.srcDirs = [
'aidl'
- $$GRADLE_AIDL_DIRS$$
+//DIR_AIDL_BEGIN
+//DIR_AIDL_END
]
assets.srcDirs = [
'assets'
- $$GRADLE_ASSET_DIRS$$
+//DIR_ASSETS_BEGIN
+//DIR_ASSETS_END
+
]
}
debug.jniLibs.srcDirs = [
'libs/debug'
- $$GRADLE_JNI_DIRS$$
+//DIR_JNI_DEBUG_BEGIN
+//DIR_JNI_DEBUG_END
]
release.jniLibs.srcDirs = [
'libs/release'
- $$GRADLE_JNI_DIRS$$
+//DIR_JNI_RELEASE_BEGIN
+//DIR_JNI_RELEASE_END
]
}
+// No longer used, as it's not useful for build source template
+// applicationVariants.all { variant ->
+// variant.outputs.all { output ->
+// output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk"
+// }
+// }
- applicationVariants.all { variant ->
- variant.outputs.all { output ->
- output.outputFileName = "../../../../../../../bin/android_${variant.name}.apk"
- }
- }
}
-$$GRADLE_PLUGINS$$
+//CHUNK_GLOBAL_BEGIN
+//CHUNK_GLOBAL_END
+
+
+
+
+
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index a9edc2f2f4..374d40463a 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -99,6 +99,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
static final int MAX_SINGLETONS = 64;
static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
+ static final int REQUEST_CAMERA_PERMISSION = 2;
private IStub mDownloaderClientStub;
private IDownloaderService mRemoteService;
private TextView mStatusText;
@@ -425,7 +426,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
io = new GodotIO(this);
- io.unique_id = Secure.ANDROID_ID;
+ io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
GodotLib.io = io;
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
@@ -956,6 +957,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
}
+ if (p_name.equals("CAMERA")) {
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
+ return false;
+ }
+ }
return true;
}
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 5e94bc457b..1a63d6ff75 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -568,7 +568,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
f->close();
if (is_execute) {
// Chmod with 0755 if the file is executable
- f->_chmod(file, 0755);
+ FileAccess::set_unix_permissions(file, 0755);
}
memdelete(f);
} else {
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 15e8f33eae..e986c47b40 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -195,7 +195,9 @@ def configure_msvc(env, manual_msvc_config):
## Compile/link flags
- env.AppendUnique(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo', '/utf-8'])
+ env.AppendUnique(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo'])
+ if int(env['MSVC_VERSION'].split('.')[0]) >= 14: #vs2015 and later
+ env.AppendUnique(CCFLAGS=['/utf-8'])
env.AppendUnique(CXXFLAGS=['/TP']) # assume all sources are C++
if manual_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
@@ -328,7 +330,7 @@ def configure_mingw(env):
env.Append(CCFLAGS=['-DWASAPI_ENABLED'])
env.Append(CCFLAGS=['-DWINMIDI_ENABLED'])
env.Append(CCFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']])
- env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt','avrt'])
+ env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt', 'avrt', 'uuid'])
env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 1a5050a15a..193a3fa2c6 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -53,6 +53,7 @@
#include <avrt.h>
#include <direct.h>
+#include <knownfolders.h>
#include <process.h>
#include <regstr.h>
#include <shlobj.h>
@@ -2460,7 +2461,7 @@ void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent,
DeleteDC(hMainDC);
}
-Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
+Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
if (p_blocking && r_pipe) {
@@ -2479,7 +2480,13 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
char buf[65535];
while (fgets(buf, 65535, f)) {
+ if (p_pipe_mutex) {
+ p_pipe_mutex->lock();
+ }
(*r_pipe) += buf;
+ if (p_pipe_mutex) {
+ p_pipe_mutex->unlock();
+ }
}
int rv = _pclose(f);
@@ -2870,39 +2877,41 @@ String OS_Windows::get_godot_dir_name() const {
String OS_Windows::get_system_dir(SystemDir p_dir) const {
- int id;
+ KNOWNFOLDERID id;
switch (p_dir) {
case SYSTEM_DIR_DESKTOP: {
- id = CSIDL_DESKTOPDIRECTORY;
+ id = FOLDERID_Desktop;
} break;
case SYSTEM_DIR_DCIM: {
- id = CSIDL_MYPICTURES;
+ id = FOLDERID_Pictures;
} break;
case SYSTEM_DIR_DOCUMENTS: {
- id = CSIDL_PERSONAL;
+ id = FOLDERID_Documents;
} break;
case SYSTEM_DIR_DOWNLOADS: {
- id = 0x000C;
+ id = FOLDERID_Downloads;
} break;
case SYSTEM_DIR_MOVIES: {
- id = CSIDL_MYVIDEO;
+ id = FOLDERID_Videos;
} break;
case SYSTEM_DIR_MUSIC: {
- id = CSIDL_MYMUSIC;
+ id = FOLDERID_Music;
} break;
case SYSTEM_DIR_PICTURES: {
- id = CSIDL_MYPICTURES;
+ id = FOLDERID_Pictures;
} break;
case SYSTEM_DIR_RINGTONES: {
- id = CSIDL_MYMUSIC;
+ id = FOLDERID_Music;
} break;
}
- WCHAR szPath[MAX_PATH];
- HRESULT res = SHGetFolderPathW(NULL, id, NULL, 0, szPath);
+ PWSTR szPath;
+ HRESULT res = SHGetKnownFolderPath(id, 0, NULL, &szPath);
ERR_FAIL_COND_V(res != S_OK, String());
- return String(szPath);
+ String path = String(szPath);
+ CoTaskMemFree(szPath);
+ return path;
}
String OS_Windows::get_user_data_dir() const {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c15e1cabc3..0e0b9bf3f6 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -261,7 +261,7 @@ public:
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 5f7b825f5e..94a87a7c90 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -58,11 +58,12 @@ def get_opts():
return [
BoolVariable('use_llvm', 'Use the LLVM compiler', False),
+ BoolVariable('use_lld', 'Use the LLD linker', False),
BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False),
BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False),
BoolVariable('use_lsan', 'Use LLVM/GCC compiler leak sanitizer (LSAN))', False),
- BoolVariable('pulseaudio', 'Detect & use pulseaudio', True),
+ BoolVariable('pulseaudio', 'Detect and use PulseAudio', True),
BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
@@ -130,6 +131,12 @@ def configure(env):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env.extra_suffix = ".llvm" + env.extra_suffix
+ if env['use_lld']:
+ if env['use_llvm']:
+ env.Append(LINKFLAGS=['-fuse-ld=lld'])
+ else:
+ print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
+ sys.exit(255)
if env['use_ubsan'] or env['use_asan'] or env['use_lsan']:
env.extra_suffix += "s"
@@ -148,6 +155,7 @@ def configure(env):
if env['use_lto']:
env.Append(CCFLAGS=['-flto'])
+
if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
else:
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index c96047dfbd..f6161a9485 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1165,7 +1165,7 @@ int OS_X11::get_screen_dpi(int p_screen) const {
int height_mm = DisplayHeightMM(x11_display, p_screen);
double xdpi = (width_mm ? sc.width / (double)width_mm * 25.4 : 0);
double ydpi = (height_mm ? sc.height / (double)height_mm * 25.4 : 0);
- if (xdpi || xdpi)
+ if (xdpi || ydpi)
return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1);
//could not get dpi
@@ -3036,34 +3036,40 @@ bool OS_X11::is_vsync_enabled() const {
*/
void OS_X11::set_context(int p_context) {
- char *config_name = NULL;
XClassHint *classHint = XAllocClassHint();
if (classHint) {
- char *wm_class = (char *)"Godot";
- if (p_context == CONTEXT_EDITOR)
- classHint->res_name = (char *)"Godot_Editor";
- if (p_context == CONTEXT_PROJECTMAN)
- classHint->res_name = (char *)"Godot_ProjectList";
+ CharString name_str;
+ switch (p_context) {
+ case CONTEXT_EDITOR:
+ name_str = "Godot_Editor";
+ break;
+ case CONTEXT_PROJECTMAN:
+ name_str = "Godot_ProjectList";
+ break;
+ case CONTEXT_ENGINE:
+ name_str = "Godot_Engine";
+ break;
+ }
+ CharString class_str;
if (p_context == CONTEXT_ENGINE) {
- classHint->res_name = (char *)"Godot_Engine";
- String config_name_tmp = GLOBAL_GET("application/config/name");
- if (config_name_tmp.length() > 0) {
- config_name = strdup(config_name_tmp.utf8().get_data());
+ String config_name = GLOBAL_GET("application/config/name");
+ if (config_name.length() == 0) {
+ class_str = "Godot_Engine";
} else {
- config_name = strdup("Godot Engine");
+ class_str = config_name.utf8();
}
-
- wm_class = config_name;
+ } else {
+ class_str = "Godot";
}
- classHint->res_class = wm_class;
+ classHint->res_class = class_str.ptrw();
+ classHint->res_name = name_str.ptrw();
XSetClassHint(x11_display, x11_window, classHint);
XFree(classHint);
- free(config_name);
}
}