Skip to content

Commit ca613e1

Browse files
malysclaude
andcommitted
fix(radio): undo the playback the vendor's tune starts on its own
1.1.0 dropped the srcPlayRadio call after tuning and assumed that was enough to change station in silence. It is not. RadioService's own tune calls AudioController.requestMuted(false), which requests the audio focus and unmutes the tuner, so the radio starts playing on every tune whether or not the caller asked for it — read off the decompiled radioservice in apks/. Not playing therefore has to be undone rather than skipped. tune takes an andPlay flag and owns the outcome: true plays as before, false calls the new pause (srcPauseRadio, transaction 28) as soon as the station is set. The limitation left is the vendor's: pause mutes the tuner but does not hand the audio focus back — the service only abandons it on loss, and for AM/FM never — so whatever was playing before does not resume. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent c456d6c commit ca613e1

2 files changed

Lines changed: 44 additions & 5 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@ All notable changes to this project are documented here. Format follows
44
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
55
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [1.2.0] - 2026-08-22
8+
9+
### Added
10+
11+
- `SaicRadio.pause`, the vendor service's `srcPauseRadio` — the counterpart of `play`. It
12+
mutes the tuner and marks the radio stopped; it does not hand the audio focus back, which
13+
the vendor service only does when it loses it.
14+
15+
### Changed
16+
17+
- `SaicRadio.tune` takes an `andPlay` flag and is responsible for the outcome. 1.1.0 removed
18+
the `srcPlayRadio` call and assumed that was enough to tune in silence; it is not. The
19+
vendor's `tune` calls `AudioController.requestMuted(false)` itself, which requests the
20+
audio focus and unmutes the tuner, so changing station always starts the radio. Not
21+
playing is therefore something that has to be undone after the fact: `andPlay = false`
22+
pauses the radio as soon as it is tuned. Callers must pass the flag — there is no default.
23+
24+
### Known limitation
25+
26+
- Tuning with `andPlay = false` leaves the radio holding the audio focus, silent. Whatever
27+
was playing before does not resume: the vendor service exposes no way to give the focus
28+
back for AM/FM, only for DAB scanning.
29+
730
## [1.1.0] - 2026-08-22
831

932
### Changed

‎lib/src/main/java/com/evsuite/hardware/saic/SaicMedia.kt‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ object SaicRadio {
1818
private const val TX_TUNE = 8
1919
private const val TX_START_ACTIVITY = 26
2020
private const val TX_SRC_PLAY = 27
21+
private const val TX_SRC_PAUSE = 28
2122

2223
/** `RadioType`: 1 = AM, 2 = FM, 4 = DAB. */
2324
const val BAND_AM = 1
@@ -43,13 +44,28 @@ object SaicRadio {
4344
SaicAidl.callBoolean(service.binder(), DESCRIPTOR, TX_START_ACTIVITY) ?: false
4445

4546
/**
46-
* Tunes a frequency in kHz (FM 87500–108000), without touching the audio source.
47+
* Silences the radio and marks it stopped — `srcPauseRadio`, the counterpart of [play].
4748
*
48-
* Tuning and playing are kept apart because a caller may want the station set without
49-
* the radio taking over what is currently playing; [play] is the explicit second step.
49+
* It mutes the tuner rather than handing the audio focus back: the vendor service only
50+
* abandons focus when it loses it, so whatever was playing before the radio took over
51+
* does not resume on its own. Silence is the most this service offers.
5052
*/
51-
fun tune(band: Int, frequencyKhz: Int): Boolean =
52-
SaicAidl.callVoid(service.binder(), DESCRIPTOR, TX_TUNE, band, frequencyKhz)
53+
fun pause(): Boolean = SaicAidl.callVoid(service.binder(), DESCRIPTOR, TX_SRC_PAUSE)
54+
55+
/**
56+
* Tunes a frequency in kHz (FM 87500–108000), playing it or leaving it silent.
57+
*
58+
* [andPlay] is not optional decoration on top of the tune: `tune` itself calls
59+
* `AudioController.requestMuted(false)` inside the vendor service, which requests the
60+
* audio focus and unmutes the tuner, so the radio starts playing whether or not anyone
61+
* asked it to. A caller that wants the station set without the sound has to undo that,
62+
* which is why the choice is made here rather than left to a second call the caller can
63+
* forget: `andPlay = false` pauses the radio again as soon as it is tuned.
64+
*/
65+
fun tune(band: Int, frequencyKhz: Int, andPlay: Boolean): Boolean {
66+
if (!SaicAidl.callVoid(service.binder(), DESCRIPTOR, TX_TUNE, band, frequencyKhz)) return false
67+
return if (andPlay) play() else pause()
68+
}
5369
}
5470

5571
/**

0 commit comments

Comments
 (0)