@@ -129,25 +129,68 @@ object PowerWindows {
129129
130130 private fun calKey (window : PowerWindow , part : String ) = " win_cal_${window.name.lowercase(Locale .ROOT )} _$part "
131131
132- fun calibration (context : Context , window : PowerWindow ): WindowCalibration ? {
132+ private const val KEY_COURSE_MS = " win_course_ms"
133+ private const val KEY_CAL_ADVANCED = " win_cal_advanced"
134+
135+ /* * Durée de course retenue pour les vitres sans calibrage propre, lue une fois par le worker. */
136+ @Volatile
137+ private var courseMs = WindowCommand .DEFAULT_COURSE_MS
138+
139+ fun courseMs (context : Context ): Long = WindowCommand .clampCourseMs(
140+ context.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE )
141+ .getLong(KEY_COURSE_MS , WindowCommand .DEFAULT_COURSE_MS ))
142+
143+ fun setCourseMs (context : Context , ms : Long ) {
144+ val valeur = WindowCommand .clampCourseMs(ms)
145+ context.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE ).edit {
146+ putLong(KEY_COURSE_MS , valeur)
147+ }
148+ courseMs = valeur
149+ AppLogger .i(TAG , " durée de course : $valeur ms" )
150+ }
151+
152+ /* *
153+ * Calibrage par vitre, option avancée.
154+ *
155+ * Éteint, chaque vitre sans capteur suit la durée de course générale, **mais les mesures déjà
156+ * faites restent enregistrées** : rallumer l'option les remet en service sans refaire
157+ * l'assistant. À la première lecture, l'option s'allume d'elle-même si des mesures existent
158+ * déjà — personne ne doit perdre sa précision à la mise à jour.
159+ */
160+ fun advancedCalibration (context : Context ): Boolean {
161+ val prefs = context.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE )
162+ if (! prefs.contains(KEY_CAL_ADVANCED )) {
163+ val dejaCalibre = PowerWindow .entries.any { storedCalibration(context, it) != null }
164+ prefs.edit { putBoolean(KEY_CAL_ADVANCED , dejaCalibre) }
165+ if (dejaCalibre) AppLogger .i(TAG , " calibrage existant : option avancée activée d'office" )
166+ return dejaCalibre
167+ }
168+ return prefs.getBoolean(KEY_CAL_ADVANCED , false )
169+ }
170+
171+ fun setAdvancedCalibration (context : Context , on : Boolean ) {
172+ context.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE ).edit {
173+ putBoolean(KEY_CAL_ADVANCED , on)
174+ }
175+ AppLogger .i(TAG , " calibrage par vitre ${if (on) " activé" else " désactivé" } " )
176+ // Les estimateurs portent la calibration : ils doivent repartir de la nouvelle règle.
177+ reloadEstimators()
178+ }
179+
180+ /* * Mesures enregistrées pour cette vitre, sans tenir compte de l'option avancée. */
181+ private fun storedCalibration (context : Context , window : PowerWindow ): WindowCalibration ? {
133182 if (window.hasPositionSensor) return null
134183 val prefs = context.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE )
135184 val down = prefs.getLong(calKey(window, " down_ms" ), 0L )
136185 val up = prefs.getLong(calKey(window, " up_ms" ), 0L )
137186 return WindowCalibration (down, up).takeIf { WindowCalibration .isValidMeasure(down) && WindowCalibration .isValidMeasure(up) }
138187 }
139188
140- /* * Enregistre la calibration ; l'assistant finit sur une montée complète, la vitre est donc fermée. */
141- /* *
142- * Vitres sans capteur dont la calibration manque encore.
143- *
144- * Sert de garde-fou à la fermeture automatique : elle ferme au temps mesuré, une vitre non
145- * calibrée partirait sur la course par défaut sans que personne puisse le vérifier depuis
146- * l'extérieur de la voiture.
147- */
148- fun uncalibrated (context : Context ): List <PowerWindow > =
149- PowerWindow .entries.filter { ! it.hasPositionSensor && calibration(context, it) == null }
189+ /* * Calibrage réellement appliqué : null quand l'option avancée est éteinte. */
190+ fun calibration (context : Context , window : PowerWindow ): WindowCalibration ? =
191+ if (advancedCalibration(context)) storedCalibration(context, window) else null
150192
193+ /* * Enregistre la calibration ; l'assistant finit sur une montée complète, la vitre est donc fermée. */
151194 fun saveCalibration (context : Context , window : PowerWindow , cal : WindowCalibration ) {
152195 context.getSharedPreferences(PREFS_NAME , Context .MODE_PRIVATE ).edit {
153196 putLong(calKey(window, " down_ms" ), cal.downMs)
@@ -161,9 +204,19 @@ object PowerWindows {
161204 * Sur [worker] : charge une fois les calibrations enregistrées. Chaque vitre calibrée part fermée
162205 * (0 %) : cas le plus courant, sans exiger de course complète au démarrage de l'app.
163206 */
207+ /* * Relit calibrations et durée de course après un changement de réglage. */
208+ private fun reloadEstimators () {
209+ worker.post {
210+ estimators.clear()
211+ estimatorsLoaded = false
212+ loadEstimators()
213+ }
214+ }
215+
164216 private fun loadEstimators () {
165217 if (estimatorsLoaded) return
166218 val context = MG4Hardware .appContext() ? : return
219+ courseMs = courseMs(context)
167220 PowerWindow .entries.forEach { w ->
168221 val cal = calibration(context, w) ? : return @forEach
169222 estimators[w] = WindowEstimator (cal).apply { setClosed() }
@@ -231,7 +284,7 @@ object PowerWindows {
231284 */
232285 fun closeForCalibration (window : PowerWindow ) {
233286 lastAutoMs.remove(window)
234- worker.post { startAuto(window, Direction .UP , " calibration" , minEmulatedMs = WindowCommand . EMULATED_COURSE_MS ) }
287+ worker.post { startAuto(window, Direction .UP , " calibration" , minEmulatedMs = courseMs ) }
235288 }
236289
237290 /* * Sur [worker]. Course automatique : native pour le conducteur, émulée pour les autres vitres. */
@@ -251,7 +304,7 @@ object PowerWindows {
251304 */
252305 private fun startEmulatedCourse (window : PowerWindow , direction : Direction , origin : String , minMs : Long = 0L) {
253306 loadEstimators()
254- val ms = maxOf(minMs, WindowCommand .emulatedCourseMs(direction, estimators[window]?.calibration))
307+ val ms = maxOf(minMs, WindowCommand .emulatedCourseMs(direction, estimators[window]?.calibration, courseMs ))
255308 val what = if (direction == Direction .UP ) " fermeture" else " ouverture"
256309 startRepeat(window, WindowCommand .manual(direction), ms, finger = false , label = " $origin , $what auto émulée" )
257310 }
@@ -354,7 +407,7 @@ object PowerWindows {
354407 // Ajout APRÈS le démarrage : remplacer une course d'une séquence précédente ne
355408 // doit pas compter comme l'interruption de celle-ci.
356409 startRepeat(w, WindowCommand .MANUAL_UP ,
357- WindowCommand .emulatedCourseMs(Direction .UP , estimators[w]?.calibration),
410+ WindowCommand .emulatedCourseMs(Direction .UP , estimators[w]?.calibration, courseMs ),
358411 finger = false , label = origin, autoClose = true )
359412 autoClosePending + = w
360413 }
0 commit comments