Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Refactor icon logic and make monochrome icon optional #99378

Merged
merged 2 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 59 additions & 6 deletions platform/android/export/export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,18 @@ static const char *MISMATCHED_VERSIONS_MESSAGE = "Android build version mismatch

static const char *GDEXTENSION_LIBS_PATH = "libs/gdextensionlibs.json";

// This template string must always match the content of 'platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml'.
static const String ICON_XML_TEMPLATE =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n"
" <background android:drawable=\"@mipmap/icon_background\"/>\n"
" <foreground android:drawable=\"@mipmap/icon_foreground\"/>\n"
"%s" // Placeholder for the optional monochrome tag.
"</adaptive-icon>";

static const String ICON_XML_PATH = "res/mipmap-anydpi-v26/icon.xml";
static const String THEMED_ICON_XML_PATH = "res/mipmap-anydpi-v26/themed_icon.xml";

static const int icon_densities_count = 6;
static const char *launcher_icon_option = PNAME("launcher_icons/main_192x192");
static const char *launcher_adaptive_icon_foreground_option = PNAME("launcher_icons/adaptive_foreground_432x432");
Expand Down Expand Up @@ -1709,6 +1721,8 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
const Ref<Image> &p_monochrome) {
String gradle_build_dir = ExportTemplateManager::get_android_build_directory(p_preset);

String monochrome_tag = "";

// Prepare images to be resized for the icons. If some image ends up being uninitialized,
// the default image from the export template will be used.

Expand Down Expand Up @@ -1742,8 +1756,12 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
_process_launcher_icons(launcher_adaptive_icon_monochromes[i].export_path, p_monochrome,
launcher_adaptive_icon_monochromes[i].dimensions, data);
store_file_at_path(gradle_build_dir.path_join(launcher_adaptive_icon_monochromes[i].export_path), data);
monochrome_tag = " <monochrome android:drawable=\"@mipmap/icon_monochrome\"/>\n";
}
}

// Finalize the icon.xml by formatting the template with the optional monochrome tag.
store_string_at_path(gradle_build_dir.path_join(ICON_XML_PATH), vformat(ICON_XML_TEMPLATE, monochrome_tag));
}

Vector<EditorExportPlatformAndroid::ABI> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
Expand Down Expand Up @@ -1783,12 +1801,6 @@ String EditorExportPlatformAndroid::get_export_option_warning(const EditorExport
if (!is_package_name_valid(pn, &pn_err)) {
return TTR("Invalid package name:") + " " + pn_err;
}
} else if (p_name == launcher_adaptive_icon_monochrome_option) {
String monochrome_icon_path = p_preset->get(launcher_adaptive_icon_monochrome_option);

if (monochrome_icon_path.is_empty()) {
return TTR("No adaptive monochrome icon specified; default Godot monochrome icon will be used.");
}
} else if (p_name == "gradle_build/use_gradle_build") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
String enabled_plugins_names = _get_plugins_names(Ref<EditorExportPreset>(p_preset));
Expand Down Expand Up @@ -3451,6 +3463,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");

Vector<ABI> invalid_abis(enabled_abis);

//To temporarily store icon xml data.
Vector<uint8_t> themed_icon_xml_data;
int icon_xml_compression_method = -1;

while (ret == UNZ_OK) {
//get filename
unz_file_info info;
Expand Down Expand Up @@ -3480,6 +3497,20 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_fix_resources(p_preset, data);
}

if (file == THEMED_ICON_XML_PATH) {
// Store themed_icon.xml data.
themed_icon_xml_data = data;
skip = true;
}

if (file == ICON_XML_PATH) {
if (monochrome.is_valid() && !monochrome->is_empty()) {
// Defer processing of icon.xml until after themed_icon.xml is read.
icon_xml_compression_method = info.compression_method;
skip = true;
}
}

if (file.ends_with(".png") && file.contains("mipmap")) {
for (int i = 0; i < icon_densities_count; ++i) {
if (main_image.is_valid() && !main_image->is_empty()) {
Expand Down Expand Up @@ -3549,6 +3580,28 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
ret = unzGoToNextFile(pkg);
}

// Process deferred icon.xml and replace it's data with themed_icon.xml.
if (monochrome.is_valid() && !monochrome->is_empty()) {
print_line("ADDING: " + ICON_XML_PATH + " (replacing with themed_icon.xml data)");

const bool uncompressed = icon_xml_compression_method == 0;
zip_fileinfo zipfi = get_zip_fileinfo();

zipOpenNewFileInZip(unaligned_apk,
ICON_XML_PATH.utf8().get_data(),
&zipfi,
nullptr,
0,
nullptr,
0,
nullptr,
uncompressed ? 0 : Z_DEFLATED,
Z_DEFAULT_COMPRESSION);

zipWriteInFileInZip(unaligned_apk, themed_icon_xml_data.ptr(), themed_icon_xml_data.size());
zipCloseFileInZip(unaligned_apk);
}

if (!invalid_abis.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Missing libraries in the export template for the selected architectures: %s. Please build a template with all required libraries, or uncheck the missing architectures in the export preset."), join_abis(invalid_abis, ", ", false)));
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
Expand Down
4 changes: 3 additions & 1 deletion platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
WARNING: The content of this file must always match the constant 'platform/android/export/export_plugin.cpp#ICON_XML_TEMPLATE'.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/icon_background"/>
<foreground android:drawable="@mipmap/icon_foreground"/>
<monochrome android:drawable="@mipmap/icon_monochrome"/>
</adaptive-icon>
11 changes: 11 additions & 0 deletions platform/android/java/lib/res/mipmap-anydpi-v26/themed_icon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is created to work alongside the icon.xml file.
If the user provides a Monochrome icon in the export settings, its data will be used to overwrite the icon.xml file.
We needed to create this file to get a reference for icon_monochrome.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/icon_background"/>
<foreground android:drawable="@mipmap/icon_foreground"/>
<monochrome android:drawable="@mipmap/icon_monochrome"/>
</adaptive-icon>