diff --git a/shell/plugins/services/battery/BatteryModel.js b/shell/plugins/services/battery/BatteryModel.js index 2aca5dbd92b..04883bdc63c 100644 --- a/shell/plugins/services/battery/BatteryModel.js +++ b/shell/plugins/services/battery/BatteryModel.js @@ -12,10 +12,17 @@ function shouldWarnLowBattery(device, onBattery, dischargingState, threshold, al if (level < 0) return { level: level, notify: false, notifiedLowBattery: false } var low = isDischarging(device, onBattery, dischargingState) && level <= threshold + + // Hysteresis: once warned, stay latched until the battery recovers well above + // the threshold. Clearing the latch the moment the device is not both + // discharging and at/under the threshold lets a brief charging/pending/unknown + // UPower blip at a still-low percentage re-arm the warning, so the next poll + // re-fires the critical notification and copies stack up on screen. + var recovered = level >= threshold + 10 return { level: level, notify: low && !alreadyNotified, - notifiedLowBattery: low + notifiedLowBattery: (alreadyNotified || low) && !recovered } } diff --git a/test/shell.d/battery-test.sh b/test/shell.d/battery-test.sh index 0447779a96f..591673a0ee0 100644 --- a/test/shell.d/battery-test.sh +++ b/test/shell.d/battery-test.sh @@ -28,4 +28,19 @@ assertDeepEqual( { level: 40, notify: false, notifiedLowBattery: false }, 'battery clears notified state after recovery' ) +assertDeepEqual( + battery.shouldWarnLowBattery({ isPresent: true, percentage: 0.1, state: discharging }, false, discharging, 10, true), + { level: 10, notify: false, notifiedLowBattery: true }, + 'battery holds the latch through a non-discharging blip at a still-low level' +) +assertDeepEqual( + battery.shouldWarnLowBattery({ isPresent: true, percentage: 0.15, state: discharging }, true, discharging, 10, true), + { level: 15, notify: false, notifiedLowBattery: true }, + 'battery holds the latch above the threshold until it recovers past the re-arm level' +) +assertDeepEqual( + battery.shouldWarnLowBattery({ isPresent: true, percentage: 0.2, state: discharging }, true, discharging, 10, true), + { level: 20, notify: false, notifiedLowBattery: false }, + 'battery clears the latch once it recovers to the re-arm level' +) JS