Skip to content
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
44 changes: 44 additions & 0 deletions scripts/release/configure_android_system_bars.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,49 @@ def configure_activity(source: str) -> str:
)


_MANIFEST_ICON = 'android:icon="@mipmap/ic_launcher"'
_MANIFEST_ROUND_ICON = 'android:roundIcon="@mipmap/ic_launcher_round"'
_KEEP_XML = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<resources xmlns:tools="http://schemas.android.com/tools"\n'
' tools:keep="@mipmap/ic_launcher,@mipmap/ic_launcher_round,'
'@mipmap/ic_launcher_foreground,@color/ic_launcher_background" />\n'
)


def configure_manifest_round_icon(manifest_source: str) -> str:
"""Ensure AndroidManifest.xml references @mipmap/ic_launcher_round so AGP 9 R8 keeps it."""

if _MANIFEST_ROUND_ICON in manifest_source:
return manifest_source
if _MANIFEST_ICON not in manifest_source:
raise ValueError("unsupported Tauri AndroidManifest template")
return manifest_source.replace(
_MANIFEST_ICON,
f"{_MANIFEST_ICON}\n {_MANIFEST_ROUND_ICON}",
1,
)


def preserve_launcher_resources(activity_path: Path) -> None:
"""Wire android:roundIcon in AndroidManifest.xml and write res/raw/keep.xml."""

main_dir = next((p for p in activity_path.parents if p.name == "main"), None)
if main_dir is None:
return
manifest_path = main_dir / "AndroidManifest.xml"
if manifest_path.is_file():
original_manifest = manifest_path.read_text()
updated_manifest = configure_manifest_round_icon(original_manifest)
if updated_manifest != original_manifest:
manifest_path.write_text(updated_manifest)
res_dir = main_dir / "res"
if res_dir.is_dir() or manifest_path.is_file():
keep_path = res_dir / "raw" / "keep.xml"
keep_path.parent.mkdir(parents=True, exist_ok=True)
keep_path.write_text(_KEEP_XML)


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--activity", type=Path, required=True)
Expand All @@ -87,6 +130,7 @@ def main() -> int:
configured = configure_activity(original)
if configured != original:
args.activity.write_text(configured)
preserve_launcher_resources(args.activity)
print(f"configured Android system bars: {args.activity}")
return 0

Expand Down
33 changes: 32 additions & 1 deletion tests/release/test_configure_android_system_bars.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from __future__ import annotations

from pathlib import Path

import pytest

from scripts.release.configure_android_system_bars import configure_activity
from scripts.release.configure_android_system_bars import (
configure_activity,
configure_manifest_round_icon,
preserve_launcher_resources,
)

TAURI_ACTIVITY = """package io.termflow.client

Expand Down Expand Up @@ -31,6 +37,31 @@ def test_configures_orientation_aware_transient_status_bar_once() -> None:
assert configure_activity(configured) == configured


def test_preserves_round_launcher_icon_in_manifest_and_keep_xml(tmp_path: Path) -> None:
main_dir = tmp_path / "src" / "main"
activity = main_dir / "java" / "io" / "termflow" / "client" / "MainActivity.kt"
activity.parent.mkdir(parents=True, exist_ok=True)
activity.write_text(TAURI_ACTIVITY)
manifest = main_dir / "AndroidManifest.xml"
manifest.write_text(
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
' <application\n'
' android:icon="@mipmap/ic_launcher"\n'
' android:label="@string/app_name">\n'
' </application>\n'
'</manifest>\n'
)

preserve_launcher_resources(activity)

updated = manifest.read_text()
assert 'android:roundIcon="@mipmap/ic_launcher_round"' in updated
assert configure_manifest_round_icon(updated) == updated
keep_xml = main_dir / "res" / "raw" / "keep.xml"
assert keep_xml.is_file()
assert "@mipmap/ic_launcher_round" in keep_xml.read_text()


@pytest.mark.parametrize(
"source",
[
Expand Down
Loading