feat(android): a padlock icon instead of Delphi's default

Cyan on slate, the accent the desktop app already uses. Adaptive vectors for
Android 8+ - background covering the full 108 units since the launcher applies
its own mask, foreground kept inside the central 66 that no mask can crop -
plus a monochrome layer for Android 13 themed icons, where the keyhole has to
be a hole in the path rather than a shape in another colour.

PNGs for older launchers come from make-icons.ps1, same drawing, and carry
their own rounded square since nothing masks them.

They are copied over Delphi's in repack-apk.ps1, for the same reason as
libsk4d.so: the Android_LauncherIcon and Android_AdaptiveIcon properties ought
to be enough, and nothing deploys them here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-08-15 16:11:31 +01:00
parent 65e6ba6a54
commit 202b93c246
5 changed files with 137 additions and 0 deletions
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Fond de l'icone adaptative. Le systeme y applique son propre masque
(rond, carre arrondi, goutte selon le lanceur), donc il doit couvrir les
108 unites entieres : tout ce qui manque devient un bord blanc. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#0F172A"
android:pathData="M0,0h108v108h-108z" />
</vector>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Avant-plan de l'icone adaptative : un cadenas.
TOUT DOIT TENIR DANS LES 66 UNITES CENTRALES (soit 21..87) : le systeme
recadre et anime la couche autour de cette zone sure, et ce qui deborde
peut etre rogne selon le lanceur. Le dessin ci-dessous occupe 34..74. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<!-- Anse : trait, pas remplissage, pour garder l'interieur ajoure. -->
<path
android:strokeColor="#22D3EE"
android:strokeWidth="5.5"
android:strokeLineCap="round"
android:fillColor="#00000000"
android:pathData="M44,56 L44,47 A10,10 0 0 1 64,47 L64,56" />
<!-- Corps -->
<path
android:fillColor="#22D3EE"
android:pathData="M38,54 L70,54 A4,4 0 0 1 74,58 L74,76 A4,4 0 0 1 70,80 L38,80 A4,4 0 0 1 34,76 L34,58 A4,4 0 0 1 38,54 Z" />
<!-- Serrure, evidee dans la couleur du fond -->
<path
android:fillColor="#0F172A"
android:pathData="M54,62 m-4,0 a4,4 0 1,0 8,0 a4,4 0 1,0 -8,0 Z" />
<path
android:fillColor="#0F172A"
android:pathData="M52.2,66 L55.8,66 L55,73.5 L53,73.5 Z" />
</vector>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Version monochrome, pour les icones themees d'Android 13+. Le systeme
ignore les couleurs et ne garde que la silhouette, qu'il teinte selon le
fond d'ecran. La serrure doit donc etre un TROU dans le trace, pas une
forme d'une autre couleur - d'ou le remplissage evenOdd plutot que deux
chemins superposes. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:strokeColor="#FFFFFF"
android:strokeWidth="5.5"
android:strokeLineCap="round"
android:fillColor="#00000000"
android:pathData="M44,56 L44,47 A10,10 0 0 1 64,47 L64,56" />
<path
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:pathData="M38,54 L70,54 A4,4 0 0 1 74,58 L74,76 A4,4 0 0 1 70,80 L38,80 A4,4 0 0 1 34,76 L34,58 A4,4 0 0 1 38,54 Z M54,62 m-4,0 a4,4 0 1,0 8,0 a4,4 0 1,0 -8,0 Z M52.2,66 L55.8,66 L55,73.5 L53,73.5 Z" />
</vector>
+68
View File
@@ -0,0 +1,68 @@
# Genere les icones PNG du lanceur, pour Android < 8 qui ignore les icones
# adaptatives. Meme dessin que les vecteurs de android-res\drawable :
# cadenas cyan sur ardoise.
#
# A relancer seulement si le dessin change ; les PNG sont suivis par git.
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
$root = Join-Path $PSScriptRoot 'android-res'
$bg = [System.Drawing.Color]::FromArgb(255, 15, 23, 42) # #0F172A
$fg = [System.Drawing.Color]::FromArgb(255, 34, 211, 238) # #22D3EE
# densite -> cote en pixels, tel qu'Android les attend
$sizes = @{ 'drawable-ldpi' = 36; 'drawable-mdpi' = 48; 'drawable-hdpi' = 72
'drawable-xhdpi' = 96; 'drawable-xxhdpi' = 144; 'drawable-xxxhdpi' = 192 }
foreach ($dir in $sizes.Keys) {
$n = $sizes[$dir]
$out = Join-Path $root $dir
New-Item -ItemType Directory -Force $out | Out-Null
$bmp = New-Object System.Drawing.Bitmap $n, $n
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.SmoothingMode = 'AntiAlias'
# Fond : carre arrondi. Les vieux lanceurs ne masquent pas, donc l'icone
# doit porter sa propre forme.
$r = [int]($n * 0.22)
$path = New-Object System.Drawing.Drawing2D.GraphicsPath
$path.AddArc(0, 0, 2*$r, 2*$r, 180, 90)
$path.AddArc($n-2*$r-1, 0, 2*$r, 2*$r, 270, 90)
$path.AddArc($n-2*$r-1, $n-2*$r-1, 2*$r, 2*$r, 0, 90)
$path.AddArc(0, $n-2*$r-1, 2*$r, 2*$r, 90, 90)
$path.CloseFigure()
$g.FillPath((New-Object System.Drawing.SolidBrush $bg), $path)
# Echelle : le dessin vectoriel vit dans un carre de 108.
$u = $n / 108.0
$brush = New-Object System.Drawing.SolidBrush $fg
$pen = New-Object System.Drawing.Pen $fg, ([float](5.5 * $u))
$pen.StartCap = 'Round'; $pen.EndCap = 'Round'
# Anse : demi-cercle ouvert vers le bas, puis deux montants.
$g.DrawArc($pen, [float](44*$u), [float](37*$u), [float](20*$u), [float](20*$u), 180, 180)
$g.DrawLine($pen, [float](44*$u), [float](47*$u), [float](44*$u), [float](56*$u))
$g.DrawLine($pen, [float](64*$u), [float](47*$u), [float](64*$u), [float](56*$u))
# Corps
$body = New-Object System.Drawing.Drawing2D.GraphicsPath
$bx = 34*$u; $by = 54*$u; $bw = 40*$u; $bh = 26*$u; $br = 4*$u
$body.AddArc([float]$bx, [float]$by, [float](2*$br), [float](2*$br), 180, 90)
$body.AddArc([float]($bx+$bw-2*$br), [float]$by, [float](2*$br), [float](2*$br), 270, 90)
$body.AddArc([float]($bx+$bw-2*$br), [float]($by+$bh-2*$br), [float](2*$br), [float](2*$br), 0, 90)
$body.AddArc([float]$bx, [float]($by+$bh-2*$br), [float](2*$br), [float](2*$br), 90, 90)
$body.CloseFigure()
$g.FillPath($brush, $body)
# Serrure, evidee dans la couleur du fond
$bgBrush = New-Object System.Drawing.SolidBrush $bg
$g.FillEllipse($bgBrush, [float](50*$u), [float](58*$u), [float](8*$u), [float](8*$u))
$g.FillRectangle($bgBrush, [float](52.4*$u), [float](64*$u), [float](3.2*$u), [float](9*$u))
$g.Dispose()
$bmp.Save((Join-Path $out 'ic_launcher.png'), [System.Drawing.Imaging.ImageFormat]::Png)
$bmp.Dispose()
"{0,-20} {1}x{1}" -f $dir, $n
}
+5
View File
@@ -21,6 +21,11 @@ $p = '.\Android64\Debug\pmserverApk'
# 1. Remettre Skia, que Deploy vient d'effacer.
Copy-Item "$bds\binandroid64\libsk4d.so" "$p\library\lib\arm64-v8a\libsk4d.so" -Force
# 1 bis. Nos icones par-dessus celles de Delphi. Meme raison que pour Skia :
# les proprietes Android_LauncherIcon* et Android_AdaptiveIcon* du .dproj
# devraient suffire, mais rien ne les deploie ici.
Copy-Item "$PSScriptRoot\android-res\*" "$p\res\" -Recurse -Force
# 2. aapt : reconstruit l'archive non alignee depuis library, classes, res.
& $pac -u8 --aaptpackage="$sdk\build-tools\33.0.2\Aapt.exe,$p\library,$p\classes,$p\res,$p\assets,$p\AndroidManifest.xml,$sdk\platforms\android-33\android.jar,$p\bin\pmserverApk-unaligned.apk"
if ($LASTEXITCODE -ne 0) { throw "aapt a echoue" }