031041adea
The Wear OS companion app's MediaController caches the MediaSession
token at first bind. When our idle timer fired super.stop() — which
calls stopSelf() on the AudioService and makes it eligible for OS
destruction under memory pressure — the next play() spun up a fresh
MediaSession with a different token. The companion's cached controller
still pointed at the dead one, so transport taps from notification
+ watch silently no-op'd even though PlaybackState broadcasts kept
flowing (those go through the live session). User-side workaround
was unpair/repair of the Watch.
Split stop() into:
- _softTeardown: stops the player, clears mediaItem/queue, broadcasts
idle. Display surfaces drop their visible state (this is what made
notification + watch tile cleanup work today; not super.stop()).
- stop(): _softTeardown + super.stop(). Reserved for explicit close
(onTaskRemoved while idle).
_onIdleTimeout now calls _softTeardown — the FGS + MediaSession stay
alive across idle, preserving the Wear binding. Explicit user-close
still terminates the service fully.
Diagnostic debugPrints from the investigation phase removed.
Research: ryanheise/audio_service 0.18.18 has been stale ~13 months,
no Media3 migration in flight upstream. This is the surgical fix
that respects the plugin's lifecycle contract.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>