Close the SDD cycle for the ring architecture replacement: verified with one critical (channel silence by omission) fixed and re-checked before archive, delta merged into the main native-alarms spec (2 requirements removed, 5 added), artifacts archived byte-for-byte. Phase 3 on-device QA (9 items) remains the mandatory human gate.
5.1 KiB
Delta for native-alarms
Ring audio moves from the Dart/native handoff + STREAM_MUSIC override to one native owner on STREAM_ALARM for the whole ring. System volumes are never written; nothing needs restoring.
ADDED Requirements
Requirement: Sole native ring-audio ownership
PluriWaveAlarmService MUST be the only audio source for the whole ring, on STREAM_ALARM via its own MediaPlayer. No Dart player or second audible source MUST play.
Scenario: Media volume 0 does not silence the ring
Testability: on-device QA (audio routing) + flutter test with fakes
- GIVEN device
STREAM_MUSICvolume is 0 - WHEN an alarm fires
- THEN it MUST be audible via the service's
STREAM_ALARMplayer - AND no Dart audio path (
EstadoRadio) MUST run
Scenario: Fire notification posts with no sound
Testability: code-inspection + on-device QA
- GIVEN channel
pluriwave_alarm_fire_v3 - WHEN the ringing notification posts
- THEN it MUST carry no sound; the player MUST be the only audible source
Scenario: Three-stage fallback preserved, single fade anchor
Testability: code-inspection + on-device QA
- GIVEN the primary station fails within its timeout
- WHEN the service advances station -> fallback station -> WAV
- THEN whichever stage starts MUST get the same fade curve, anchored at ring start
Requirement: Exponential dB fade-in ceiling
With fadeInSegundos > 0: gainDb = fraction*40-40, curve = 10^(gainDb/20) on a 50ms tick, setVolume(s * curve), s = per-alarm volumen as ceiling. With fadeInSegundos == 0: start directly at s.
Scenario: Fade rises exponentially to the ceiling
Testability: code-inspection (curve formula)
- GIVEN
fadeInSegundos > 0,volumen = s - WHEN the ring starts
- THEN volume at
t=0MUST equals * 10^(-40/20)(~1% ofs), rising every 50ms - AND volume at
t=fadeInSegundosMUST equal exactlys
Scenario: No-fade path starts pop-free
Testability: code-inspection + on-device QA
- GIVEN
fadeInSegundos == 0 - WHEN the ring starts
- THEN
setVolume(s)MUST be applied beforestart(), with no pop
Requirement: Manual transient focus; no system volume writes
The service MUST request AUDIOFOCUS_GAIN_TRANSIENT on STREAM_ALARM and abandon it at ring end. setStreamVolume MUST NOT be called on any stream, ever.
Scenario: Focus requested at start, abandoned at end
Testability: code-inspection + on-device QA (dumpsys audio)
- GIVEN the ring is about to start
- WHEN
startAlarmruns - THEN
AUDIOFOCUS_GAIN_TRANSIENTMUST be requested onSTREAM_ALARM - AND WHEN the ring ends THEN focus MUST be abandoned
Scenario: Dismiss, snooze, and back tear down with nothing to restore
Testability: on-device QA + flutter test with fakes
- GIVEN an alarm is ringing
- WHEN the user dismisses, snoozes, or triggers back
- THEN the player MUST stop, focus MUST be abandoned, and foreground removed
- AND no
setStreamVolumecall MUST have occurred for this ring
Requirement: Notification channel migration v2 -> v3
The service MUST create pluriwave_alarm_fire_v3 (no sound) and delete pluriwave_alarm_fire_v2 exactly once, guarded by a migration flag (same pattern as v1->v2).
Scenario: v2 deleted exactly once on upgrade
Testability: code-inspection (migration guard) + on-device QA
- GIVEN a device with
pluriwave_alarm_fire_v2already created - WHEN the service next ensures its channel
- THEN
_v3MUST be created and_v2deleted; a re-run MUST be a no-op
Requirement: Ring screen is pure UI
PantallaAlarmaSonando MUST only call EstadoAlarmas.finalizarEjecucion/posponerAlarma from Stop/Snooze/back. It MUST NOT control any audio player or volume/handoff channel. PuertoAlarmasAndroid MUST NOT expose confirmarAudioFlutter, forzarVolumenMediaParaAlarma, or restaurarVolumenMedia.
Scenario: Buttons and back call only EstadoAlarmas
Testability: flutter test with fakes
- GIVEN the ringing screen is displayed
- WHEN Stop, a Snooze option, or back is triggered
- THEN only
finalizarEjecucion/posponerAlarmaMUST be called - AND zero calls MUST reach
EstadoRadio.audioor a removed channel method
Scenario: Reduced Android port surface
Testability: static/compile-verifiable (Dart analyzer) + flutter test
- GIVEN
PuertoAlarmasAndroidand its implementations/fakes - WHEN inspected after this change
- THEN
confirmarAudioFlutter,forzarVolumenMediaParaAlarma,restaurarVolumenMediaMUST NOT exist
REMOVED Requirements
Requirement: Ring-scoped device-volume override
(Reason: STREAM_MUSIC is never overridden now — native rings exclusively on STREAM_ALARM, independent of the media-volume knob. Replaced by "Sole native ring-audio ownership" and "Manual transient focus; no system volume writes" above.)
Requirement: Single fade-in driver across native-to-Flutter handoff
(Reason: the handoff no longer exists; native owns the fade for the whole ring, so only one ramp ever runs. Replaced by "Exponential dB fade-in ceiling" above.)
Non-Functional Notes
- No new user-visible strings; no l10n work required across the 13 supported locales.