--- issueRef: "#174" version: 4 updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} updatedAt: 1785321673382 --- ## #174 — Cadrage Main (2026-07-28) ### Symptôme utilisateur Parfois, au lancement d'un chrono, l'affichage ne reste pas sur GameTime et retourne à l'accueil de la montre. ### Position Ce ticket est un **suivi plus précis** de `#127`, mais avec un déclencheur confirmé supplémentaire : le lancement/changement d'état du chrono. ### Attendu - tant qu'une séance est active, le retour gestuel ou le réveil écran doit favoriser le retour à GameTime ; - un changement de projection de séance ou de chrono ne doit pas éjecter l'utilisateur hors de l'app ; - l'app montre doit rester le point de focus naturel pendant la séance, sans demander de relancer manuellement l'app. ### Axes à instruire ensuite - ongoing activity / reprise d'activité ; - task affinity / launch mode / intent de retour ; - interaction entre foreground service, écran ambient et navigation Flutter ; - différence entre "écran éteint puis réveil" et "lancement d'un chrono". ## Cadrage Architect (2026-07-28) Statut : **cadrage exploitable, prêt pour lot frontend natif montre**. ### Causes techniques plausibles - `MainActivity` Wear est trop passive : pas de `onResume`, pas de `onNewIntent`, pas de logique de reentry/resync. - La reprise dépend surtout du flux Flutter `EventChannel` et de `requestLatestProjection(...)`, sans ré-ancrage explicite de l'activity. - Les intents ongoing/notification utilisent seulement `SINGLE_TOP | CLEAR_TOP`, sans action dédiée "ouvrir la séance active". - Si `POST_NOTIFICATIONS` manque, l'ongoing activity peut ne pas fournir de point d'ancrage système. - Le foreground service watch ne tourne que pour `phase == running`, donc l'UI peut perdre son point d'appui natif pendant certaines transitions alors que la séance existe encore. ### Correctif minimal recommandé - Corriger côté watch natif, sans changement de contrat métier. - Ajouter une vraie voie de réentrée locale : - intent explicite `ACTION_OPEN_ACTIVE_SESSION` ; - même intent réutilisé par ongoing activity et foreground notification ; - `onNewIntent` et `onResume` dans `MainActivity` qui appellent `requestLatestProjection(...)` + `requestCapabilityRefresh(...)`. - Garder côté natif la dernière projection utile reçue ; si elle indique une séance active **encore fraîche ou rapidement reconfirmée**, la réouverture doit retomber sur GameTime, pas sur l'accueil système. - Si la séance n'est plus confirmée, ne pas forcer de reopen : cela doit rester distingué de `#175`. ### Impacts - Contrats bridge : aucun changement obligatoire. - Natif watch : - action/extra de reentry ; - cache de dernière projection utile ; - resync explicite sur resume/new intent. - UI Flutter montre : pas de changement structurel, au plus un resync plus agressif au retour foreground. - DevBackend : non requis pour le correctif minimal. ### Garde-fous vs #175 - `#174` : le téléphone est vivant, la séance existe, mais l'activity montre décroche ou ne se ré-ancre pas. - `#175` : la projection doit expirer quand la source téléphone disparaît durablement. - Donc le reopen forcé de `#174` ne doit se faire que si la projection locale est encore fraîche ou si un resync confirme rapidement la séance. ### Lots recommandés 1. `F1 [DevFrontend] Reentry natif montre` 2. `F2 [DevFrontend] Robustesse réveil/ambient` 3. `QA1 [QA] Validation montre ancrée`