Skip to content

Commit 466a969

Browse files
committed
Add Garage mode + Popup for update
1 parent 613b4a1 commit 466a969

17 files changed

Lines changed: 933 additions & 48 deletions

File tree

‎README.md‎

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,72 @@ d'origine reste inchangé (Faible → Moyen → Fort → Adaptatif).
155155
Écran organisé en **quatre onglets** :
156156
- **Langues** : français, anglais, allemand, espagnol, italien, portugais
157157
- **Interface** : écran affiché au démarrage, apparence (auto / sombre / clair)
158-
- **Réglages avancés** : application automatique du profil, vérification des mises à jour au
159-
lancement, **canal bêta**, extinction du véhicule écran allumé, blocage des réglages de conduite
160-
au-delà d'une vitesse donnée, **API externe** (cf. section dédiée)
158+
- **Réglages avancés** : **Mode Garage** (cf. ci-dessous), vérification des mises à jour au
159+
lancement, **alerte de mise à jour sur l'écran du véhicule**, **canal bêta**, extinction du
160+
véhicule écran allumé, blocage des réglages de conduite au-delà d'une vitesse donnée,
161+
**API externe** (cf. section dédiée)
161162
- **Infos** : vérification des mises à jour, nettoyage des APK, **consommation de données**
162163
(aujourd'hui, semaine en cours, mois courant, 30 derniers jours), dialog « À propos » (version de
163164
l'app, firmware, QR codes), indicateur de firmware, et bouton Diagnostic révélé par 5 clics sur
164165
le logo
165166

167+
### Mode Garage
168+
Un seul interrupteur met MG4Control **en veille complète**, sans rien désinstaller ni
169+
reconfigurer. Il répond à un cas concret : laisser la voiture à l'atelier sans qu'un technicien
170+
voie des réglages changer seuls au contact, ni un bouton du volant faire autre chose que prévu.
171+
172+
Ce que le mode suspend, ce sont les comportements **autonomes** — ceux que personne n'a demandés
173+
sur le moment :
174+
175+
| Suspendu | Détail |
176+
|---|---|
177+
| Raccourcis classiques | La touche repart au launcher |
178+
| Raccourcis avancés | Les touches réclamées sont **rendues** : le service d'accessibilité ne consomme plus rien |
179+
| Profil au démarrage et au contact | Y compris la résolution Bluetooth |
180+
| Automatisations par température | Profil comme climatisation |
181+
| Baisse de volume à l'ouverture de porte | |
182+
| API externe | Les commandes tierces sont refusées |
183+
| Alerte de mise à jour sur l'écran du véhicule | |
184+
185+
Ce qu'il ne touche pas : l'application elle-même. Ouvrir MG4Control et appliquer un profil à la
186+
main reste possible — c'est une action de l'utilisateur, pas un comportement observable par
187+
quelqu'un qui ne fait que rouler.
188+
189+
**Rien n'est effacé.** Repasser l'interrupteur sur OFF rend l'ensemble à l'identique, profils,
190+
raccourcis et automatisations compris.
191+
192+
La notification persistante affiche « Mode Garage — en veille » tant qu'il est actif : sans ce
193+
repère, un mode oublié se manifesterait par « plus rien ne marche » sans la moindre explication.
194+
195+
> [!NOTE]
196+
> Le Mode Garage **remplace** l'ancien interrupteur « le profil par défaut s'applique
197+
> automatiquement au lancement », dont il est la version complète. Qui l'avait décoché est repris
198+
> en Mode Garage activé à la première ouverture : couper l'application était bien l'intention.
199+
200+
### Alerte de mise à jour sur l'écran du véhicule
201+
Une mise à jour ne se découvre plus seulement en ouvrant MG4Control : un message apparaît
202+
**par-dessus l'infodivertissement**, comme le popup de confirmation de profil, et annonce la
203+
version installée face à la nouvelle. Trois choix :
204+
205+
| Bouton | Effet |
206+
|---|---|
207+
| **Installer la MAJ** | Ouvre MG4Control sur le dialogue de mise à jour habituel, sans refaire la requête réseau |
208+
| **Ignorer cette version** | Cette version n'est plus proposée, ni ici ni au lancement de l'application |
209+
| **Ne plus me prévenir** | Coupe ce popup. Le dialogue au lancement de MG4Control, lui, reste |
210+
211+
Toucher le fond assombri vaut « plus tard » : rien n'est retenu, l'annonce reviendra.
212+
213+
Quatre garde-fous, parce que ce chemin n'est déclenché par personne :
214+
- la vérification a lieu **20 s après le coup de contact** — au moment même, la liaison données de
215+
la voiture n'est pas encore montée ;
216+
- **six heures minimum** entre deux interrogations réseau, la voiture étant sur un forfait données ;
217+
- **rien ne s'affiche en roulant** (même verrou que le popup multiprofils) ;
218+
- une version déjà proposée ne l'est plus dans la même session — et le marquage n'a lieu que si le
219+
popup est **réellement apparu**.
220+
221+
L'interrupteur historique « vérifier les mises à jour au lancement » coupe aussi ce popup : c'est
222+
un réglage que l'utilisateur croit global, et il l'est.
223+
166224
### Profils
167225
- Liste des profils avec application, définition par défaut, modification, suppression
168226
- **Éditeur en plein écran** organisé en trois catégories : Conduite, Sécurité, Confort
@@ -315,13 +373,15 @@ MG4Control/
315373
│ │ ├── service/
316374
│ │ │ ├── MG4ControlService.kt # Service de premier plan (boot, raccourcis, API externe)
317375
│ │ │ ├── ProfilePickerOverlay.kt# Sélecteur de profil en fenêtre flottante
318-
│ │ │ └── ProfileConfirmOverlay.kt # Confirmation OUI/NON des automatisations
376+
│ │ │ ├── ProfileConfirmOverlay.kt # Confirmation OUI/NON des automatisations
377+
│ │ │ └── UpdateOverlay.kt # Popup « MAJ disponible » sur l'écran du véhicule
319378
│ │ │
320379
│ │ ├── receiver/
321380
│ │ │ └── BootReceiver.kt # Récepteur de démarrage système
322381
│ │ │
323382
│ │ ├── util/
324383
│ │ │ ├── FirmwareInfo.kt # Détection firmware + mode forcé
384+
│ │ │ ├── GarageMode.kt # Mode Garage — met tous les automatismes en veille
325385
│ │ │ ├── FirmwareHelper.kt # Lecture version firmware complète (async)
326386
│ │ │ ├── LocaleHelper.kt # Gestion de la langue (6 langues)
327387
│ │ │ ├── ThemeHelper.kt # Thème auto / sombre / clair
@@ -330,6 +390,7 @@ MG4Control/
330390
│ │ ├── update/
331391
│ │ │ ├── UpdateChecker.kt # Vérification des releases GitHub (stable et bêta)
332392
│ │ │ ├── UpdateDialogManager.kt # Dialog MAJ + DownloadManager
393+
│ │ │ ├── UpdateNotifier.kt # Quand signaler une MAJ sur l'écran du véhicule
333394
│ │ │ ├── UpdateInfo.kt # Description d'une version disponible
334395
│ │ │ ├── ApkSecurity.kt # Contrôle de signature de l'APK téléchargé
335396
│ │ │ ├── ApkInstaller.kt # Installation
@@ -886,13 +947,68 @@ behaviour stands unchanged (Low → Medium → High → Adaptive).
886947
Screen organised into **four tabs**:
887948
- **Languages**: French, English, German, Spanish, Italian, Portuguese
888949
- **Interface**: screen shown at startup, appearance (auto / dark / light)
889-
- **Advanced**: automatic profile application, update check at launch, **beta channel**, power the
890-
car off while keeping the screen on, block driving settings above a given speed, **external API**
891-
(see the dedicated section)
950+
- **Advanced**: **Garage mode** (see below), update check at launch, **update alert on the
951+
vehicle screen**, **beta channel**, power the car off while keeping the screen on, block driving
952+
settings above a given speed, **external API** (see the dedicated section)
892953
- **Info**: update check, APK cleanup, **data usage** (today, current week, current month, last 30
893954
days), "About" dialog (app version, firmware, QR codes), firmware indicator, and a Diagnostic
894955
button revealed by 5 taps on the logo
895956

957+
### Garage mode
958+
A single switch puts MG4Control **fully to sleep**, without uninstalling or reconfiguring
959+
anything. It answers a concrete case: leaving the car at a workshop without a technician seeing
960+
settings change on their own at ignition, or a steering-wheel button doing something unexpected.
961+
962+
What the mode suspends are the **autonomous** behaviours — the ones nobody asked for at that
963+
moment:
964+
965+
| Suspended | Detail |
966+
|---|---|
967+
| Classic shortcuts | The key goes back to the launcher |
968+
| Advanced shortcuts | Claimed keys are **released**: the accessibility service consumes nothing |
969+
| Profile at startup and at ignition | Bluetooth resolution included |
970+
| Temperature automations | Profile and climate alike |
971+
| Volume drop when a door opens | |
972+
| External API | Third-party commands are refused |
973+
| Update alert on the vehicle screen | |
974+
975+
What it does not touch: the app itself. Opening MG4Control and applying a profile by hand still
976+
works — that is a user action, not a behaviour observable by someone who is only driving.
977+
978+
**Nothing is erased.** Switching it back off restores everything as it was: profiles, shortcuts
979+
and automations.
980+
981+
The persistent notification reads "Garage mode — asleep" while it is on: without that marker, a
982+
forgotten mode would show up as "nothing works any more" with no explanation whatsoever.
983+
984+
> [!NOTE]
985+
> Garage mode **replaces** the old "the default profile is applied automatically at launch"
986+
> switch, of which it is the complete version. Anyone who had unchecked it is carried over into
987+
> Garage mode on first launch: stopping the app from acting was the intent.
988+
989+
### Update alert on the vehicle screen
990+
An update is no longer found only by opening MG4Control: a message appears **over the
991+
infotainment**, like the profile confirmation popup, showing the installed version against the new
992+
one. Three choices:
993+
994+
| Button | Effect |
995+
|---|---|
996+
| **Install update** | Opens MG4Control on the usual update dialog, without repeating the network request |
997+
| **Skip this version** | That version is no longer offered, here or at app launch |
998+
| **Stop telling me** | Turns this popup off. The dialog at MG4Control launch stays |
999+
1000+
Tapping the dimmed background means "later": nothing is remembered, the alert will come back.
1001+
1002+
Four safeguards, because nobody triggers this path:
1003+
- the check runs **20 s after ignition** — at the moment itself the car's data link is not up yet;
1004+
- **six hours minimum** between network requests, the car being on a data plan;
1005+
- **nothing shows while driving** (same lock as the multi-profile popup);
1006+
- a version already offered is not offered again in the same session — and it is only marked as
1007+
offered if the popup **actually appeared**.
1008+
1009+
The long-standing "check for updates at launch" switch also turns this popup off: it is a setting
1010+
users read as global, and it is.
1011+
8961012
### Profiles
8971013
- Profile list with apply, set as default, edit and delete
8981014
- **Full-screen editor** organised into three categories: Driving, Safety, Comfort
@@ -1043,13 +1159,15 @@ MG4Control/
10431159
│ │ ├── service/
10441160
│ │ │ ├── MG4ControlService.kt # Foreground service (boot, shortcuts, external API)
10451161
│ │ │ ├── ProfilePickerOverlay.kt# Floating profile picker
1046-
│ │ │ └── ProfileConfirmOverlay.kt # YES/NO confirmation for automations
1162+
│ │ │ ├── ProfileConfirmOverlay.kt # YES/NO confirmation for automations
1163+
│ │ │ └── UpdateOverlay.kt # "Update available" popup on the vehicle screen
10471164
│ │ │
10481165
│ │ ├── receiver/
10491166
│ │ │ └── BootReceiver.kt # System boot receiver
10501167
│ │ │
10511168
│ │ ├── util/
10521169
│ │ │ ├── FirmwareInfo.kt # Firmware detection + forced mode
1170+
│ │ │ ├── GarageMode.kt # Garage mode — puts every automatism to sleep
10531171
│ │ │ ├── FirmwareHelper.kt # Full firmware version string reader (async)
10541172
│ │ │ ├── LocaleHelper.kt # Language management (6 languages)
10551173
│ │ │ ├── ThemeHelper.kt # Auto / dark / light theme
@@ -1058,6 +1176,7 @@ MG4Control/
10581176
│ │ ├── update/
10591177
│ │ │ ├── UpdateChecker.kt # GitHub release check (stable and beta)
10601178
│ │ │ ├── UpdateDialogManager.kt # Update dialog + DownloadManager
1179+
│ │ │ ├── UpdateNotifier.kt # When to announce an update on the vehicle screen
10611180
│ │ │ ├── UpdateInfo.kt # Description of an available version
10621181
│ │ │ ├── ApkSecurity.kt # Signature check of the downloaded APK
10631182
│ │ │ ├── ApkInstaller.kt # Installation

‎app/src/main/java/com/mg4/control/MainActivity.kt‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import kotlinx.coroutines.launch
2525
import kotlinx.coroutines.withContext
2626
import com.mg4.control.update.UpdateChecker
2727
import com.mg4.control.update.UpdateDialogManager
28+
import com.mg4.control.update.UpdateNotifier
2829
import com.mg4.control.util.FirmwareInfo
2930
import com.mg4.control.util.LocaleHelper
3031
import com.mg4.control.util.ThemeHelper
@@ -86,10 +87,28 @@ class MainActivity : AppCompatActivity() {
8687
setupDiagnosticUnlock()
8788
checkUnknownFirmware()
8889
navigateToDefaultScreen(savedInstanceState)
89-
checkForUpdates()
90+
// Ouverture venue du popup véhicule : la release est déjà connue, on affiche le
91+
// dialogue tout de suite plutôt que de refaire l'aller-retour réseau.
92+
val depuisPopup = UpdateNotifier.readFrom(intent)
93+
if (depuisPopup != null) UpdateDialogManager.show(this, depuisPopup)
94+
else checkForUpdates()
9095
checkProfileRestore()
9196
}
9297

98+
/**
99+
* L'application était déjà au premier plan quand le popup véhicule a été touché.
100+
*
101+
* L'intent est lancé en FLAG_ACTIVITY_SINGLE_TOP : dans ce cas Android ne recrée pas
102+
* l'activité et [onCreate] n'est jamais rappelé — sans cette surcharge, « Installer la MAJ »
103+
* ramènerait l'application au premier plan sans rien ouvrir du tout.
104+
*/
105+
override fun onNewIntent(intent: Intent) {
106+
super.onNewIntent(intent)
107+
setIntent(intent)
108+
val info = UpdateNotifier.readFrom(intent) ?: return
109+
if (!isFinishing && !isDestroyed) UpdateDialogManager.show(this, info)
110+
}
111+
93112
// ── Restauration des profils depuis la sauvegarde (après réinstallation) ──────
94113
// Ne se déclenche QUE si l'app n'a aucun profil local (vraie désinstallation /
95114
// effacement de données — pas une simple mise à jour qui conserve les données).

‎app/src/main/java/com/mg4/control/accessibility/KeyCaptureService.kt‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.mg4.control.debug.AppLogger
1212
import com.mg4.control.service.MG4ControlService
1313
import com.mg4.control.shortcut.PressType
1414
import com.mg4.control.shortcut.ShortcutAction
15+
import com.mg4.control.util.GarageMode
1516

1617
/**
1718
* Interception des touches volant, AVANT le launcher.
@@ -98,7 +99,11 @@ class KeyCaptureService : AccessibilityService() {
9899

99100
// Seules les touches explicitement enregistrées sont interceptées. Tout le reste
100101
// traverse : c'est ce qui garantit qu'un bug ici ne peut pas paralyser le volant.
101-
if (!AdvancedShortcuts.isEnabled(this) || !AdvancedShortcuts.isClaimed(this, code)) {
102+
// Mode Garage : ne RIEN consommer. C'est ici que se joue le retour des touches au
103+
// launcher d'origine — un raccourci avancé réclame sa touche en bloc, et seul un
104+
// `false` rendu ici la laisse repartir vers l'application au premier plan.
105+
if (GarageMode.isOn(this) ||
106+
!AdvancedShortcuts.isEnabled(this) || !AdvancedShortcuts.isClaimed(this, code)) {
102107
return false
103108
}
104109

‎app/src/main/java/com/mg4/control/hardware/MG4Hardware.kt‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.mg4.control.debug.AppLogger
2121
import com.mg4.control.model.DriveMode
2222
import com.mg4.control.model.RegenLevel
2323
import com.mg4.control.util.FirmwareInfo
24+
import com.mg4.control.util.GarageMode
2425
import kotlinx.coroutines.CoroutineScope
2526
import kotlinx.coroutines.Dispatchers
2627
import kotlinx.coroutines.launch
@@ -4721,8 +4722,13 @@ object MG4Hardware {
47214722
return gen == FirmwareInfo.Gen.SWI132 || gen == FirmwareInfo.Gen.SWI133
47224723
}
47234724

4724-
private fun doorVolumeEnabled(): Boolean =
4725-
sAppContext?.getSharedPreferences("mg4_settings", 0)?.getBoolean("door_volume_enabled", false) ?: false
4725+
private fun doorVolumeEnabled(): Boolean {
4726+
// Mode Garage : une portière qui fait chuter le volume est exactement le genre de
4727+
// comportement inexpliqué qu'on ne veut pas laisser observer.
4728+
if (GarageMode.isOn(sAppContext)) return false
4729+
return sAppContext?.getSharedPreferences("mg4_settings", 0)
4730+
?.getBoolean("door_volume_enabled", false) ?: false
4731+
}
47264732

47274733
private fun doorVolumeLevel(): Int =
47284734
sAppContext?.getSharedPreferences("mg4_settings", 0)?.getInt("door_volume_level", 0) ?: 0

0 commit comments

Comments
 (0)