feat(connection): ADB foreground fallback on the watchdog cadence when the protocol push is silent (store priority protocol > ADB); audio-playback hint filtered through SYSTEM_MEDIA_PACKAGES (P3-2b,c)

This commit is contained in:
James Mackay committed 2026-10-08 10:33:38 +01:00
1 parent f1e49a661b
commit 8885ddd5b5
3 files changed
+51 -4

No files matched your search

+34 -4
View File
@@ -36,6 +36,7 @@ from .const import (
ADB_RECONNECT_BACKOFF_START,
ADB_RECONNECT_JITTER,
STATE_STORE_TTL,
SYSTEM_MEDIA_PACKAGES,
)
from .ha_adb_common import MediaSessionInfo, parse_audio_playback
@@ -53,11 +54,21 @@ FIELD_IS_AVAILABLE = "is_available"
FIELD_CURRENT_APP = "current_app"
FIELD_VOLUME_INFO = "volume_info"
# ADB fallback foreground identity (P3-2): stamped only when the protocol
# push is silent; consumers prefer FIELD_CURRENT_APP over this.
FIELD_FOREGROUND = "foreground"
# ADB-derived fields (cleared when the ADB connection goes down — they are
# regenerated by the watchdog); protocol pushes (IS_ON/IS_AVAILABLE/
# CURRENT_APP/VOLUME_INFO) are device-reported truth and expire by TTL only,
# so an ADB outage never clobbers them.
ADB_FIELDS = (FIELD_AWAKE, FIELD_SESSIONS, FIELD_AUDIO_PLAYBACK, FIELD_RUNNING_APPS)
ADB_FIELDS = (
FIELD_AWAKE,
FIELD_SESSIONS,
FIELD_AUDIO_PLAYBACK,
FIELD_RUNNING_APPS,
FIELD_FOREGROUND,
)
PROTOCOL_FIELDS = (
FIELD_IS_ON,
FIELD_IS_AVAILABLE,
@@ -371,6 +382,12 @@ class ShieldConnectionManager:
"""Protocol current-app push (raw package; name resolution deferred)."""
return self.store.get(FIELD_CURRENT_APP)
@property
def foreground_app(self) -> str | None:
"""Best foreground identity: protocol push first, ADB parse fallback
(P3-2 store priority: FIELD_CURRENT_APP > FIELD_FOREGROUND)."""
return self.store.get(FIELD_CURRENT_APP) or self.store.get(FIELD_FOREGROUND)
@property
def volume_info(self) -> tuple | None:
"""Protocol volume push as ``(level, max, muted)`` — readout only
@@ -598,10 +615,23 @@ class ShieldConnectionManager:
# Full dump, no truncation (B4) — low sessions must not be lost.
await poller.poll_media_sessions(head_lines=None)
self.store.set(FIELD_SESSIONS, list(poller.all_sessions))
self.store.set(
FIELD_AUDIO_PLAYBACK, parse_audio_playback(poller.last_dump or "")
)
# Zero-cost hint from the same dump; system processes filtered
# (mediashell/systemui/tv settings/diagtools report "audio").
playback = [
pkg
for pkg in parse_audio_playback(poller.last_dump or "")
if pkg not in SYSTEM_MEDIA_PACKAGES
]
self.store.set(FIELD_AUDIO_PLAYBACK, playback)
self.store.set(FIELD_RUNNING_APPS, await poller.poll_running_apps())
# Foreground fallback (P3-2): ADB parse only when the protocol
# push is silent — store priority is protocol > ADB, so this
# never overwrites a live push.
if self.store.get(FIELD_CURRENT_APP) is None:
foreground = await poller.poll_foreground()
if foreground:
self.store.set(FIELD_FOREGROUND, foreground)
self._cache_last_known(foreground)
else:
# Standby: playback data is not current — expire it.
self.store.set(FIELD_SESSIONS, [])