Icône de l’application
Procédure de génération et structure de l’icône de lancement Android.
Statut actuel — placeholder
L’icône actuelle est un placeholder pour builds internes, dérivée du drapeau historique HFR (flag1.gif, 14 × 11, pixel art teal/rose avec bordure noire). Elle sera remplacée par une identité visuelle propre à Redface 2 avant toute publication publique.
La source vit en dehors du repo (~/Téléchargements/flag1.gif sur la machine de dev). Les ressources générées sont dans app/src/main/res/.
Structure (adaptive icon + legacy fallback)
minSdk 29 ⇒ toutes les cibles supportent les adaptive icons (API 26+). On fournit quand même les PNG legacy pour les launchers qui n’utilisent pas encore la structure adaptive.
app/src/main/res/
├── drawable/
│ └── ic_launcher_background.xml # solid color #FFFFFF (contraste avec la bordure noire du drapeau)
├── mipmap-anydpi-v26/
│ ├── ic_launcher.xml # <adaptive-icon> fg+bg
│ └── ic_launcher_round.xml # idem, pour le slot roundIcon
├── mipmap-{mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi}/
│ ├── ic_launcher.png # fallback legacy carré (avec bg intégré)
│ ├── ic_launcher_round.png # fallback legacy (launchers applique un mask rond)
│ └── ic_launcher_foreground.png # foreground de l'adaptive icon (transparent)
AndroidManifest.xml :
<application
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" ... />
Icônes alternatives
Réglages → Affichage → Icône de l’application ouvre une galerie de deux icônes complètes. Les aperçus chargent leurs ressources adaptatives : le masque est celui du système Android.
| Choix | Alias du manifeste | Composition |
|---|---|---|
| Classique | .LauncherClassic | Drapeau RF2 existant, fond #FFFFFF, inchangé |
| Redface 1 | .LauncherRf1 | Foreground et fond adaptatifs d’origine de Redface 1 (PNG aux cinq densités) |
La sélection reste provisoire jusqu’au bouton Appliquer. Le redémarrage suit le schéma ProcessPhoenix en quatre temps :
- L’application attend la persistance DataStore et active l’alias cible avec
DONT_KILL_APP, sans toucher aux autres : l’ancien alias est encore l’origActivityde la tâche courante. - Elle termine l’ancienne tâche avec
finishAffinity()avantstartActivity(), puis démarreLauncherIconRestartActivityavecNEW_TASK | CLEAR_TASK. Cette activité non exportée a une affinité vide, le modesingleInstance, son propre processus:launcherIconRestartet reste exclue des applications récentes. - L’activité de relance reçoit le nom de classe de l’alias cible et la route, pas un
Intentparcelable (patternUnsafeIntentLaunch) : elle valide le nom viaisKnownLauncherAliaspuis reconstruit l’intent localement. Elle tue le processus principal, puis lance l’intentMAIN/LAUNCHERde l’alias cible avecNEW_TASK. La nouvelle tâche a ainsi l’alias cible pourorigActivity. L’activité de relance se termine et quitte aussi son propre processus. - Au démarrage à froid, la réconciliation de
MainActivitydésactive les anciens alias sans re-basculer l’état de la cible déjà active. L’extra internesettings/app-icon, porté par l’intent de lancement, restaure Réglages → Affichage → Icône de l’application viaIntentDeliverydèsonCreate, sans attendreonNewIntent.
Un lancement direct avec NEW_TASK, même accompagné de MULTIPLE_TASK, ne suffit pas : le mode singleTop de MainActivity peut livrer l’intent à l’activité existante. La tâche conserve alors l’ancien alias comme origActivity et le système la ferme lorsque cet alias est désactivé. Le processus de relance survit à la mort du processus principal pour effectuer un lancement à froid. Si le passage à l’activité de relance échoue, l’application rétablit Classique avant de retenter la relance. Le lanceur peut rafraîchir son cache avec quelques secondes de retard.
Chaque alias cible .MainActivity et porte son propre filtre MAIN / LAUNCHER. MainActivity conserve les filtres VIEW des deep links HFR. Les alias .LauncherDark, .LauncherRose et .LauncherRed et leurs ressources restent déclarés pour les installations dev 0.54.0, mais ne sont plus proposés. Leurs valeurs persistées se lisent comme CLASSIC, sans écriture à la lecture. Au démarrage de MainActivity, le contrôleur vérifie les états effectifs des cinq composants sur le dispatcher IO : un ancien alias actif ou l’absence d’alias actif entraîne un retour à Classique et sa persistance ; les autres écarts suivent la préférence sélectionnable. Ce contrôle partage un verrou avec Appliquer et devient sans effet une fois les états cohérents.
RF1 fournit une couche <monochrome> à partir de son foreground. Classique conserve ses XML existants, sans couche monochrome dédiée. Aucun PNG legacy RF1 n’est nécessaire avec minSdk 29. Origine, licence Apache 2.0 et adaptation : mentions des assets tiers.
Pour ajouter une icône :
- fournir son foreground et son fond, avec leurs crédits ;
- ajouter les adaptive icons normale et ronde, plus la couche monochrome si disponible ;
- déclarer un
activity-aliasdésactivé par défaut dans le manifeste ; - étendre
AppLauncherIcon,launcherAliasForet le mapping de ressources côté:app; - vérifier les tests d’exclusivité des alias, de persistance avant application et de restauration.
Dimensions (108dp canvas adaptive + 48dp legacy)
| Densité | Adaptive foreground | Legacy icon |
|---|---|---|
| mdpi | 108 × 108 | 48 × 48 |
| hdpi | 162 × 162 | 72 × 72 |
| xhdpi | 216 × 216 | 96 × 96 |
| xxhdpi | 324 × 324 | 144 × 144 |
| xxxhdpi | 432 × 432 | 192 × 192 |
Le drapeau source fait 14 × 11 (ratio 14:11) : on l’upscale en nearest-neighbor (-filter point) pour préserver l’esthétique pixel art. Pour l’adaptive foreground, il occupe 60 % de la largeur du canvas, centré (bien à l’intérieur de la safe zone circulaire de 66 dp). Pour les icônes legacy, il occupe 70 % de la largeur sur fond #FFFFFF.
Régénération
Script reproductible avec ImageMagick :
cd /tmp && rm -rf icon_gen && mkdir -p icon_gen && cd icon_gen
magick ~/Téléchargements/flag1.gif[0] flag.png
# Adaptive foreground (transparent background, pixel art preserved)
for name in "mdpi 108" "hdpi 162" "xhdpi 216" "xxhdpi 324" "xxxhdpi 432"; do
d=${name%% *}; s=${name##* }
fw=$((s * 60 / 100)); fh=$((fw * 11 / 14))
magick -size ${s}x${s} xc:transparent \
\( flag.png -filter point -resize ${fw}x${fh}\! \) -gravity center -composite \
foreground_${d}.png
done
# Legacy square (flag on #FFFFFF, pixel art preserved)
for name in "mdpi 48" "hdpi 72" "xhdpi 96" "xxhdpi 144" "xxxhdpi 192"; do
d=${name%% *}; s=${name##* }
fw=$((s * 70 / 100)); fh=$((fw * 11 / 14))
magick -size ${s}x${s} xc:"#FFFFFF" \
\( flag.png -filter point -resize ${fw}x${fh}\! \) -gravity center -composite \
legacy_${d}.png
done
Puis copier dans app/src/main/res/mipmap-{densité}/ sous les noms ic_launcher_foreground.png (adaptive) et ic_launcher.png + ic_launcher_round.png (legacy).
Remplacement futur
Quand une identité visuelle dédiée sera disponible :
- Supprimer les PNG et XML générés depuis
mipmap-*+drawable/ic_launcher_background.xml. - Régénérer via Android Studio (
New → Image Asset) qui produit la même structure avec le crop et les densités corrects. - Mettre à jour cette page et retirer la mention “placeholder”.