diff --git a/lib/ble/band_status_l10n.dart b/lib/ble/band_status_l10n.dart index 5267a476b..b77af69c4 100644 --- a/lib/ble/band_status_l10n.dart +++ b/lib/ble/band_status_l10n.dart @@ -70,6 +70,13 @@ BandStatus localizedBandStatus(BuildContext c, BandStatus s) { l?.bandStatusClockLostReason ?? s.reason, fix: l?.bandStatusClockLostFix ?? s.fix, ); + case BandCondition.firmwareLocked: + return BandStatus( + s.condition, + l?.bandStatusFirmwareLockedTitle ?? s.title, + l?.bandStatusFirmwareLockedReason ?? s.reason, + fix: l?.bandStatusFirmwareLockedFix ?? s.fix, + ); case BandCondition.connected: return BandStatus( s.condition, diff --git a/lib/ble/ble_engine.dart b/lib/ble/ble_engine.dart index 2bea5e677..b9ea39787 100644 --- a/lib/ble/ble_engine.dart +++ b/lib/ble/ble_engine.dart @@ -2832,6 +2832,7 @@ class BleEngine { strapNeedsReboot: state.strapNeedsReboot, syncClockLost: state.syncClockLost, bondRefusals: state.bondRefusals, + bandFirmware: state.firmware, ); /// Read past pre-init/resetting states without an unbounded startup await. @@ -6299,6 +6300,7 @@ class BleEngine { } state.charging = h.charging; state.wristOn = h.wristOn; + state.firmware = h.firmwareVersion; onState(state); unawaited(LocalDb.noteBandFirmware(h.firmwareVersion)); _log('[HELLO gen5] serial=${h.serial} fw=${h.firmwareVersion} ' @@ -6311,6 +6313,11 @@ class BleEngine { // battery figure as if they were read, which is the same imputation // the quarantine above exists to stop. The revision and the body // length are the two things true at any layout. + // + // Firmware is CLEARED, not kept: a version from an earlier HELLO must + // not survive to drive the 50.43 lock status for this one. The rev-3 + // reader below stays diagnostics-only. + state.firmware = null; _log('[HELLO gen5] revision ${h.helloRevision} is not the revision-1 ' 'layout these offsets read (body ${h.rawHex.length ~/ 2}B) — ' 'serial, battery, charge and wrist state are NOT published or ' diff --git a/lib/ble/ble_state.dart b/lib/ble/ble_state.dart index 36bc085dd..0da2ab2b0 100644 --- a/lib/ble/ble_state.dart +++ b/lib/ble/ble_state.dart @@ -223,6 +223,10 @@ enum BandCondition { /// Syncs complete carrying no sensor data — the band's clock has lost sync. clockLost, + /// The band is on a firmware that withholds all data until a WHOOP-signed + /// membership token is on it (edge#673), and no data is arriving. + firmwareLocked, + connected, connecting, scanning, @@ -271,6 +275,16 @@ class BandStatus { bool isLinkAuthRefusal(int? code) => code == 5 || code == 8 || code == 15 || code == 137; +/// True for WHOOP 5.0 / MG firmware 50.43.x, which keeps answering commands +/// but sends no history or live data until a WHOOP-signed membership token is +/// on the band (edge#673; reported on 50.43.1.0 and 50.43.2.0). +/// [firmware] is `Gen5HelloInfo.firmwareVersion` (`major.minor.build.x`). +// ponytail: a version prefix, not a probe for the token itself. A later +// firmware with the same lock needs adding here; one that lifts it on 50.43 +// still only shows this while the data flags below are tripped. +bool isDataLockedFirmware(String? firmware) => + firmware != null && firmware.startsWith('50.43.'); + /// Fold the phone-level blocker and the band's own diagnostic flags into one /// state. Pure; [connection] is `DeviceState.connection`. /// @@ -287,6 +301,7 @@ BandStatus bandStatusFor({ bool strapNeedsReboot = false, bool syncClockLost = false, int bondRefusals = 0, + String? bandFirmware, }) { const repairFix = 'Forget the band in the phone’s Bluetooth settings, ' 'then pair it again here'; @@ -355,6 +370,28 @@ BandStatus bandStatusFor({ fix: 'Reconnect the band; if it repeats tomorrow, pair it again', ); } + // The same two "no data is arriving" flags, explained by the firmware + // instead: a charger cycle or a re-pair cannot help a band that withholds + // its data by design, and both flags clear once records bank again. The + // flags cannot tell the lock from a real strap or clock fault, so the text + // says "probably", never "is". It sits BELOW the quarantine check on + // purpose: a quarantined batch is data that DID arrive, which a locked band + // does not send, so that diagnosis is the more specific one. + if ((strapNeedsReboot || syncClockLost) && + isDataLockedFirmware(bandFirmware)) { + return const BandStatus( + BandCondition.firmwareLocked, + 'The band’s firmware is probably holding back its data', + 'This band runs WHOOP firmware 50.43, which can connect and answer the ' + 'app but send no recordings or live heart rate until a ' + 'WHOOP-signed membership token is on it. That is the most likely ' + 'reason no data is arriving. OpenStrap cannot issue that token. ' + 'Everything already saved here is safe.', + fix: 'If it is the firmware, nothing in the app changes it, and this ' + 'clears once the band sends data again. If nothing arrives, ' + 'charging the band or re-pairing is still worth a try', + ); + } if (strapNeedsReboot) { return const BandStatus( BandCondition.strapUnresponsive, diff --git a/lib/data/models.dart b/lib/data/models.dart index 35b772a14..99dbd79a2 100644 --- a/lib/data/models.dart +++ b/lib/data/models.dart @@ -419,6 +419,9 @@ class DeviceState { /// EmptySyncTracker tripped: ≥3 consecutive console-only offloads — the strap's /// RTC has likely lost sync. bool syncClockLost = false; + /// Firmware the gen5 HELLO reported on this connection (`50.43.2.0`), null + /// until one has. Read by `bandStatusFor` to name a firmware data lock. + String? firmware; /// StuckStrapDetector tripped: frontier frozen while the strap is ahead — a /// defensive reboot/clock-reset was attempted. bool strapNeedsReboot = false; @@ -475,6 +478,7 @@ class DeviceState { bondRefusals = 0; autoReconnectPaused = false; syncClockLost = false; + firmware = null; strapNeedsReboot = false; syncChunkQuarantined = false; dataRangeOldest = null; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 65f18ac64..a7a8d58a6 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -3685,5 +3685,8 @@ "stepCalDoneHousehold": "Gespeichert. Dein Smartphone hat {count} der {band} Schritte gezählt, die das Band erkannt hat. Bewegung im Haushalt wird jetzt auf {gain} skaliert.", "whoopFirmwareWarningTitle": "WHOOP-Nutzer: Verbinde dich nicht wieder mit der WHOOP-App", "whoopFirmwareWarningAction": "Wenn du OpenStrap oder eine andere Open-Source-App nutzt oder später zu einer wechseln möchtest, verbinde dein Band nicht wieder mit der offiziellen WHOOP-App. Sie kann Firmware-Updates automatisch installieren. Deinstalliere oder deaktiviere die WHOOP-App, damit sie dein Band nicht aktualisiert.", - "whoopFirmwareWarningDetails": "Berichte zur WHOOP 5.0 / MG Firmware 50.43.1.0 und 50.43.2.0 beschreiben einen blockierten Datenzugriff. Bluetooth kann sich weiterhin verbinden. OpenStrap kann das von WHOOP signierte Mitgliedschafts-Token nicht ausstellen, das betroffene Bänder entsperrt. Wir arbeiten an einer Lösung, aber es gibt noch keine Abhilfe." + "whoopFirmwareWarningDetails": "Berichte zur WHOOP 5.0 / MG Firmware 50.43.1.0 und 50.43.2.0 beschreiben einen blockierten Datenzugriff. Bluetooth kann sich weiterhin verbinden. OpenStrap kann das von WHOOP signierte Mitgliedschafts-Token nicht ausstellen, das betroffene Bänder entsperrt. Wir arbeiten an einer Lösung, aber es gibt noch keine Abhilfe.", + "bandStatusFirmwareLockedTitle": "Die Firmware des Bands hält wahrscheinlich seine Daten zurück", + "bandStatusFirmwareLockedReason": "Dieses Band läuft mit WHOOP-Firmware 50.43. Sie kann sich verbinden und der App antworten, aber keine Aufzeichnungen und keine Live-Herzfrequenz senden, solange kein von WHOOP signiertes Mitgliedschafts-Token auf dem Band ist. Das ist der wahrscheinlichste Grund, warum keine Daten ankommen. OpenStrap kann dieses Token nicht ausstellen. Alles, was hier schon gespeichert ist, bleibt erhalten.", + "bandStatusFirmwareLockedFix": "Liegt es an der Firmware, lässt sich das in der App nicht ändern, und der Hinweis verschwindet, sobald das Band wieder Daten sendet. Kommen keine Daten an, lohnt sich trotzdem ein Versuch mit Laden oder neu koppeln" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b43507676..608cf3f33 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -16803,6 +16803,18 @@ "@strengthDelete": {"description": "Strength set editor copy."}, "strengthSaveFailed": "Failed to save changes", "@strengthSaveFailed": {"description": "Strength set editor copy."}, + "bandStatusFirmwareLockedTitle": "The band’s firmware is probably holding back its data", + "@bandStatusFirmwareLockedTitle": { + "description": "BandStatus card title: band firmware 50.43 withholds all data until a WHOOP membership token is on it" + }, + "bandStatusFirmwareLockedReason": "This band runs WHOOP firmware 50.43, which can connect and answer the app but send no recordings or live heart rate until a WHOOP-signed membership token is on it. That is the most likely reason no data is arriving. OpenStrap cannot issue that token. Everything already saved here is safe.", + "@bandStatusFirmwareLockedReason": { + "description": "BandStatus card body: band firmware 50.43 withholds all data until a WHOOP membership token is on it" + }, + "bandStatusFirmwareLockedFix": "If it is the firmware, nothing in the app changes it, and this clears once the band sends data again. If nothing arrives, charging the band or re-pairing is still worth a try", + "@bandStatusFirmwareLockedFix": { + "description": "BandStatus fix action: band firmware 50.43 withholds all data until a WHOOP membership token is on it" + }, "napAutoLogTitle": "Log clear naps automatically", "napAutoLogSub": "A detected nap with strong evidence is added without asking. You can still edit or remove it", "napAutoLogSaveFailed": "That setting could not be saved. Try again." diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 2cf903bc1..794442bd4 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -3385,5 +3385,8 @@ "stepCalDoneHousehold": "Guardado. Tu teléfono contó {count} de los {band} pasos que vio la banda. El movimiento en casa ahora se escala a {gain}.", "whoopFirmwareWarningTitle": "Usuarios de WHOOP: no vuelvas a conectarte a la app de WHOOP", "whoopFirmwareWarningAction": "Si usas OpenStrap u otra app de código abierto, o piensas cambiarte a una más adelante, no vuelvas a conectar tu banda a la app oficial de WHOOP. Puede instalar actualizaciones de firmware automáticamente. Desinstala o desactiva la app de WHOOP para evitar que actualice tu banda.", - "whoopFirmwareWarningDetails": "Hay informes de que el firmware 50.43.1.0 y 50.43.2.0 de WHOOP 5.0 / MG bloquea el acceso a los datos. Es posible que el Bluetooth siga conectándose. OpenStrap no puede emitir el token de membresía firmado por WHOOP que se necesita para desbloquear las bandas afectadas. Estamos trabajando en una solución, pero todavía no hay ningún arreglo disponible." + "whoopFirmwareWarningDetails": "Hay informes de que el firmware 50.43.1.0 y 50.43.2.0 de WHOOP 5.0 / MG bloquea el acceso a los datos. Es posible que el Bluetooth siga conectándose. OpenStrap no puede emitir el token de membresía firmado por WHOOP que se necesita para desbloquear las bandas afectadas. Estamos trabajando en una solución, pero todavía no hay ningún arreglo disponible.", + "bandStatusFirmwareLockedTitle": "Probablemente el firmware de la banda está reteniendo sus datos", + "bandStatusFirmwareLockedReason": "Esta banda usa el firmware 50.43 de WHOOP, que puede conectarse y responder a la app sin enviar registros ni frecuencia cardíaca en vivo hasta que haya en ella un token de membresía firmado por WHOOP. Es la razón más probable de que no lleguen datos. OpenStrap no puede emitir ese token. Todo lo que ya está guardado aquí está a salvo.", + "bandStatusFirmwareLockedFix": "Si es el firmware, la app no puede cambiarlo y el aviso desaparece cuando la banda vuelva a enviar datos. Si no llega nada, vale la pena probar a cargarla o volver a emparejarla" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 112586647..33f1944da 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -3385,5 +3385,8 @@ "pairOuraExistingKeyGuidance": "Vous utilisez déjà l’application Oura ? Gardez l’anneau associé dans cette application et associez-le avec sa clé actuelle. Passez les étapes de réinitialisation ci-dessous. Réinitialisez-le uniquement si vous voulez une nouvelle clé.", "whoopFirmwareWarningTitle": "Utilisateurs WHOOP : ne vous reconnectez pas à l’application WHOOP", "whoopFirmwareWarningAction": "Si vous utilisez OpenStrap ou une autre application open source, ou si vous comptez y passer plus tard, ne reconnectez pas votre bracelet à l’application WHOOP officielle. Elle peut installer des mises à jour du firmware automatiquement. Désinstallez ou désactivez l’application WHOOP pour l’empêcher de mettre à jour votre bracelet.", - "whoopFirmwareWarningDetails": "Des signalements concernant les firmwares 50.43.1.0 et 50.43.2.0 des WHOOP 5.0 / MG décrivent un accès aux données bloqué. Le Bluetooth peut encore se connecter. OpenStrap ne peut pas émettre le jeton d’abonnement signé par WHOOP nécessaire pour déverrouiller les bracelets concernés. Nous travaillons sur une solution, mais aucun correctif n’est encore disponible." + "whoopFirmwareWarningDetails": "Des signalements concernant les firmwares 50.43.1.0 et 50.43.2.0 des WHOOP 5.0 / MG décrivent un accès aux données bloqué. Le Bluetooth peut encore se connecter. OpenStrap ne peut pas émettre le jeton d’abonnement signé par WHOOP nécessaire pour déverrouiller les bracelets concernés. Nous travaillons sur une solution, mais aucun correctif n’est encore disponible.", + "bandStatusFirmwareLockedTitle": "Le firmware du bracelet retient probablement ses données", + "bandStatusFirmwareLockedReason": "Ce bracelet utilise le firmware WHOOP 50.43, qui peut se connecter et répondre à l’application sans envoyer ni enregistrements ni fréquence cardiaque en direct tant qu’un jeton d’abonnement signé par WHOOP n’est pas présent sur le bracelet. C’est la raison la plus probable pour laquelle aucune donnée n’arrive. OpenStrap ne peut pas émettre ce jeton. Tout ce qui est déjà enregistré ici est en sécurité.", + "bandStatusFirmwareLockedFix": "Si c’est le firmware, l’application n’y peut rien et ce message disparaît dès que le bracelet renvoie des données. Si rien n’arrive, essayez quand même de le recharger ou de le jumeler à nouveau" } diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 9ed1242ae..5891b933a 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -3037,6 +3037,9 @@ "whoopFirmwareWarningTitle": "WHOOP उपयोगकर्ता: WHOOP ऐप से दोबारा कनेक्ट न करें", "whoopFirmwareWarningAction": "अगर आप OpenStrap या कोई दूसरा ओपन-सोर्स ऐप इस्तेमाल करते हैं, या बाद में किसी पर जाने की सोच रहे हैं, तो अपना बैंड आधिकारिक WHOOP ऐप से दोबारा कनेक्ट न करें। वह फ़र्मवेयर अपडेट अपने-आप इंस्टॉल कर सकता है। WHOOP ऐप को अनइंस्टॉल या अक्षम कर दें, ताकि वह आपके बैंड को अपडेट न कर सके।", "whoopFirmwareWarningDetails": "WHOOP 5.0 / MG के फ़र्मवेयर 50.43.1.0 और 50.43.2.0 के बारे में रिपोर्टें बताती हैं कि डेटा तक पहुँच रोक दी जाती है। ब्लूटूथ फिर भी कनेक्ट हो सकता है। प्रभावित बैंड को अनलॉक करने के लिए WHOOP द्वारा साइन किया गया मेंबरशिप टोकन चाहिए, जिसे OpenStrap जारी नहीं कर सकता। हम समाधान पर काम कर रहे हैं, लेकिन अभी कोई उपाय उपलब्ध नहीं है।", + "bandStatusFirmwareLockedTitle": "बैंड का फ़र्मवेयर शायद उसका डेटा रोक रहा है", + "bandStatusFirmwareLockedReason": "यह बैंड WHOOP फ़र्मवेयर 50.43 पर चल रहा है, जो कनेक्ट होकर ऐप को जवाब दे सकता है, लेकिन जब तक बैंड पर WHOOP द्वारा साइन किया गया सदस्यता टोकन न हो, तब तक कोई रिकॉर्डिंग या लाइव हृदय गति नहीं भेजता। डेटा न आने का सबसे संभावित कारण यही है। OpenStrap वह टोकन जारी नहीं कर सकता। यहाँ पहले से सहेजा गया सब कुछ सुरक्षित है।", + "bandStatusFirmwareLockedFix": "अगर वजह फ़र्मवेयर है, तो ऐप इसे बदल नहीं सकता और बैंड के फिर से डेटा भेजते ही यह संदेश हट जाएगा। अगर कुछ नहीं आता, तो बैंड को चार्ज करना या दोबारा पेयर करना फिर भी आज़माने लायक है", "alarmNextLabel": "अगला", "alarmScheduleGroup": "साप्ताहिक शेड्यूल", "alarmWakeTimeRowTitle": "जागने का समय", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index cb40872e8..016fc54e6 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -8101,6 +8101,9 @@ } } }, + "bandStatusFirmwareLockedTitle": "Прошивка браслета, вероятно, удерживает его данные", + "bandStatusFirmwareLockedReason": "На этом браслете прошивка WHOOP 50.43: он может подключаться и отвечать приложению, но не передавать ни записи, ни пульс в реальном времени, пока на нём нет подписанного WHOOP токена подписки. Скорее всего, данные не приходят именно поэтому. OpenStrap не может выпустить такой токен. Всё, что уже сохранено здесь, в безопасности.", + "bandStatusFirmwareLockedFix": "Если дело в прошивке, приложение изменить это не может, и сообщение исчезнет, как только браслет снова начнёт передавать данные. Если ничего не приходит, всё равно стоит зарядить браслет или заново выполнить сопряжение", "pairResetWhoop5Step1": "Снимите браслет с руки и подождите, пока погаснут зелёные огоньки.", "pairResetWhoop5Step2": "Держите браслет за боковые стороны и сильно постукивайте двумя пальцами по верхней части, пока не будет мигать только синий. Если горят синий и белый вместе, продолжайте стучать, пока не останется только синий.", "pairResetWhoop5Step3": "Если приложение WHOOP установлено на этом телефоне, принудительно закройте его.", diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb index 227ddbff6..cc8891c0d 100644 --- a/lib/l10n/app_th.arb +++ b/lib/l10n/app_th.arb @@ -16487,6 +16487,9 @@ } } }, + "bandStatusFirmwareLockedTitle": "เฟิร์มแวร์ของสายรัดน่าจะกำลังกักข้อมูลไว้", + "bandStatusFirmwareLockedReason": "สายรัดนี้ใช้เฟิร์มแวร์ WHOOP 50.43 ซึ่งอาจเชื่อมต่อและตอบสนองแอปได้ แต่ไม่ส่งข้อมูลที่บันทึกไว้หรืออัตราการเต้นของหัวใจแบบสด จนกว่าจะมีโทเค็นสมาชิกที่ WHOOP ลงนามอยู่บนสายรัด นี่เป็นสาเหตุที่น่าจะเป็นที่สุดที่ไม่มีข้อมูลเข้ามา OpenStrap ไม่สามารถออกโทเค็นนั้นได้ ข้อมูลทั้งหมดที่บันทึกไว้ที่นี่แล้วยังปลอดภัย", + "bandStatusFirmwareLockedFix": "หากเป็นที่เฟิร์มแวร์ แอปแก้ไขเรื่องนี้ไม่ได้ และข้อความนี้จะหายไปเองเมื่อสายรัดส่งข้อมูลอีกครั้ง หากยังไม่มีข้อมูลเข้ามา การชาร์จหรือจับคู่ใหม่ก็ยังคุ้มค่าที่จะลอง", "pairResetWhoop5Step1": "ถอดสายรัดออกจากข้อมือ แล้วรอจนไฟสีเขียวดับ", "@pairResetWhoop5Step1": { "description": "Reset help for WHOOP 5.0 / MG, step 1." diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 52eae2f7c..b1976de88 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -3037,6 +3037,9 @@ "whoopFirmwareWarningTitle": "WHOOP 用户:请勿重新连接 WHOOP 应用", "whoopFirmwareWarningAction": "如果你在使用 OpenStrap 或其他开源应用,或打算以后改用,请不要再把手环连接到 WHOOP 官方应用。它可能会自动安装固件更新。请卸载或停用 WHOOP 应用,以免它更新你的手环。", "whoopFirmwareWarningDetails": "有报告称,WHOOP 5.0 / MG 固件 50.43.1.0 和 50.43.2.0 会阻止访问数据。蓝牙可能仍能连接。解锁受影响的手环需要由 WHOOP 签名的会员令牌,OpenStrap 无法签发。我们正在寻找解决办法,但目前还没有可用的修复。", + "bandStatusFirmwareLockedTitle": "手环固件可能正在扣留它的数据", + "bandStatusFirmwareLockedReason": "这个手环运行的是 WHOOP 固件 50.43:它可以连接并响应应用,但在手环上没有 WHOOP 签名的会员令牌之前,可能不会发送任何记录或实时心率。这是收不到数据最可能的原因。OpenStrap 无法签发这个令牌。已保存在这里的所有数据都是安全的。", + "bandStatusFirmwareLockedFix": "如果是固件的原因,应用无法更改,手环重新发送数据后此提示会自动消失。如果仍然没有数据,充电或重新配对仍然值得一试", "alarmNextLabel": "下一次", "alarmScheduleGroup": "每周计划", "alarmWakeTimeRowTitle": "起床时间", diff --git a/lib/support/issue_report.dart b/lib/support/issue_report.dart index acf8bd163..2de999227 100644 --- a/lib/support/issue_report.dart +++ b/lib/support/issue_report.dart @@ -330,6 +330,7 @@ Future<({File zip, Map meta})> collectReport( 'syncClockLost': d.syncClockLost, 'strapNeedsReboot': d.strapNeedsReboot, 'syncChunkQuarantined': d.syncChunkQuarantined, + 'bandFirmware': d.firmware, 'initError': app.initError, 'importRollupError': app.importRollupError, 'lastBackupError': app.lastBackupError, diff --git a/test/ble_state_test.dart b/test/ble_state_test.dart index e45ea0500..cfc099847 100644 --- a/test/ble_state_test.dart +++ b/test/ble_state_test.dart @@ -638,6 +638,10 @@ void main() { bandStatusFor(connection: 'connected', syncChunkQuarantined: true), bandStatusFor(connection: 'connected', strapNeedsReboot: true), bandStatusFor(connection: 'connected', syncClockLost: true), + bandStatusFor( + connection: 'connected', + strapNeedsReboot: true, + bandFirmware: '50.43.2.0'), ]; for (final s in faults) { expect(s.isFault, isTrue, reason: '${s.condition}'); @@ -712,6 +716,52 @@ void main() { ); }); + test('a 50.43 band that sends nothing is named by its firmware (#673)', () { + for (final flags in [ + (stuck: true, clock: false), + (stuck: false, clock: true), + ]) { + final s = bandStatusFor( + connection: 'connected', + strapNeedsReboot: flags.stuck, + syncClockLost: flags.clock, + bandFirmware: '50.43.2.0', + ); + expect(s.condition, BandCondition.firmwareLocked, reason: '$flags'); + expect(s.isFault, isTrue); + expect(s.reason, contains('50.43')); + // The flags cannot tell the lock from a real strap or clock fault, so + // the text must not tell the user that charging or re-pairing is + // pointless; it only says the app cannot change a firmware lock. + expect(s.fix, contains('nothing in the app changes it')); + expect(s.fix, contains('worth a try')); + expect(s.fix, isNot(contains('will not help'))); + expect(s.title, contains('probably')); + } + }); + + test('firmware alone is not a fault, and other firmware keeps its advice', + () { + // A token-unlocked 50.43 band that is syncing shows as connected. + expect( + bandStatusFor(connection: 'connected', bandFirmware: '50.43.1.0') + .condition, + BandCondition.connected, + ); + expect( + bandStatusFor( + connection: 'connected', + strapNeedsReboot: true, + bandFirmware: '50.38.1.0', + ).condition, + BandCondition.strapUnresponsive, + ); + expect(isDataLockedFirmware(null), isFalse); + expect(isDataLockedFirmware('50.43.1.0'), isTrue); + expect(isDataLockedFirmware('50.430.0.0'), isFalse); + expect(isDataLockedFirmware('5.43.0.0'), isFalse); + }); + test('the ordinary link states are not faults', () { for (final c in ['connected', 'connecting', 'scanning', 'disconnected']) { expect(bandStatusFor(connection: c).isFault, isFalse, reason: c);