test(appareil): diagnostic de montage d'écran + relevé — MIUI bloque l'installation USB

Le run rebranché est allé plus loin que jamais : connexion à .75 et lecture du schéma sur
l'appareil, puis blocage sur la lecture des charges. Un contrôle de montage de l'écran est
ajouté pour distinguer « navigation non faite » de « lecture en échec » — mais il n'a pas
pu s'exécuter : MIUI a remis à zéro « Installer via USB » à la reconnexion et refuse
désormais toute installation (INSTALL_FAILED_USER_RESTRICTED, sans dialogue). L'app n'est
de ce fait plus installée sur le téléphone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HajXLUczEyZd22JeewRfff
This commit is contained in:
Patrick Schurig 2026-08-25 22:48:09 +02:00
parent f0aa0fd804
commit 98e2874ecd
2 changed files with 38 additions and 5 deletions

View File

@ -140,7 +140,24 @@ Il n'a **pas** été mené jusqu'au bout. Trois obstacles, dans l'ordre où ils
**enregistre la box lui-même** (`connectNew`), voir l'encadré ci-dessous ;
3. **le téléphone s'est déconnecté du bus USB** (`adb: device 'dee659e2' not found`,
plus rien dans `lsusb`), et l'ADB sans fil n'est pas activé
(`connect 192.168.1.121:5555` → refusé). **C'est là que ça s'est arrêté.**
(`connect 192.168.1.121:5555` → refusé) ;
4. rebranché, le run est allé **plus loin que jamais** — connexion, schéma lu — et a buté
sur la lecture des charges. Un diagnostic de montage d'écran a été ajouté pour trancher
entre « navigation non faite » et « lecture en échec »… mais il n'a pas pu s'exécuter :
**MIUI refuse désormais toute installation par USB.**
```
adb: failed to install app-debug.apk:
Failure [INSTALL_FAILED_USER_RESTRICTED: Install canceled by user]
```
Aucune boîte de dialogue à l'écran : le refus est silencieux. Le réglage
« Installer via USB » des options développeur MIUI s'est remis à zéro à la reconnexion
— comportement connu de MIUI, et il exige un compte Xiaomi pour être réactivé.
**Conséquence immédiate : l'application n'est plus installée du tout** (`pm list
packages` ne la trouve plus), l'installation ayant échoué après la désinstallation.
**C'est là que ça s'est arrêté**, et le blocage n'est pas logiciel.
> ⚠️ **Effet de bord causé au téléphone, et assumé.** `flutter test integration_test`
> **réinstalle** l'application, ce qui vide `shared_preferences` et le stockage sécurisé :
@ -247,9 +264,12 @@ le banc pour être vérifié.
écriture n'y a été déclenchée depuis l'IU. La connexion et la lecture du schéma, elles,
l'ont été (§2). Le blocage final n'est pas logiciel : le téléphone s'est **déconnecté du
bus USB** en cours de campagne.
*Pour clore ce point* : rebrancher le téléphone (et autoriser l'ADB s'il le redemande),
puis `flutter test integration_test/config_on_device_test.dart -d dee659e2`. Le harnais
est écrit et corrigé ; il ne reste qu'à le faire tourner.
*Pour clore ce point* : réactiver **« Installer via USB »** dans les options
développeur du téléphone (MIUI l'a remis à zéro), puis
`flutter test integration_test/config_on_device_test.dart -d dee659e2`. Le harnais est
écrit et instrumenté ; il ne reste qu'à le faire tourner. Activer au passage
« Débogage USB (réglages de sécurité) » déverrouillerait aussi `adb shell input`, utile
mais non nécessaire ici.
2. **Les écritures depuis l'IU** n'ont donc été exercées qu'en **tests de widgets**, sur les
dumps réels de `.75` (`merged_config_screen_test.dart`). Le rendu, l'annonce d'impact et le
grisage y sont couverts ; le transport ne l'est pas.

View File

@ -26,6 +26,7 @@ library;
import 'package:etm_powersync_app/main.dart' as app;
import 'package:etm_powersync_app/providers/load_config_provider.dart';
import 'package:etm_powersync_app/providers/schema_provider.dart';
import 'package:etm_powersync_app/screens/energy/roles_devices_screen.dart';
import 'package:etm_powersync_app/services/connection_manager.dart';
import 'package:etm_powersync_app/services/nymea_service.dart';
import 'package:flutter/material.dart';
@ -100,9 +101,21 @@ void main() {
GoRouter.of(ctxSousRouteur).go('/energy/setup');
await tester.pump(const Duration(seconds: 3));
// L'écran DOIT être monté : c'est son initState qui branche LoadConfigProvider sur le
// service et déclenche la lecture. Si la navigation n'a pas eu lieu, le symptôme
// serait « aucune charge » — un diagnostic trompeur. On vérifie donc d'abord.
await _attendre(
tester,
() => find.byType(RolesDevicesScreen).evaluate().isNotEmpty,
quoi: 'le montage de l\'écran « Rôles & appareils »',
);
debugPrint('[appareil] écran de configuration monté');
final config = Provider.of<LoadConfigProvider>(ctx, listen: false);
await _attendre(tester, () => config.entries.isNotEmpty,
limite: const Duration(seconds: 30), quoi: 'les charges de GetLoadConfig');
limite: const Duration(seconds: 40),
quoi: 'les charges de GetLoadConfig '
'(erreur du provider : ${config.error ?? "aucune"})');
final ids = config.entries.map((e) => e.id).toList()..sort();
debugPrint('[appareil] charges lues : $ids');