Skip to content

Add the watch's own playback service and controller (issue #276) - #282

Merged
mapitman merged 1 commit into
mainfrom
issue-276-wear-playback
Sep 2, 2026
Merged

mapitman merged 1 commit into
mainfrom
issue-276-wear-playback

Conversation

@mapitman

@mapitman mapitman commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

Step 5 of #276 (see #278-281 for steps 1-4). The watch can now actually stream and play an episode from its own local (synced) queue, independent of the phone.

  • WearPlaybackUrlResolver always resolves to FeedItem.enclosureUrl — no downloaded-file branch, since phase 1 is streaming-only (regression guard for phase 2/Send downloaded episodes to Wear OS for offline playback (phase 2) #277's eventual file-transfer support).
  • WearPlaybackMediaItemFactory builds a Media3 MediaItem from a FeedItem, trimmed from :app's PlaybackMediaItemFactory: no mobile-data gating, per-feed speed, or volume boost, since none of that settings state is part of what WearQueueSyncApplier syncs onto the watch.
  • WearPlaybackService (a MediaSessionService) owns the ExoPlayer instance, auto-advances through the local queue on episode completion, and pushes its position-save loop through WearSyncClient the same way :app's PlaybackService does — trimmed from it: no preload manager/timeline lookahead, no Android Auto browse tree.
  • WearPlaybackController is a thin MediaController wrapper exposing WearPlaybackUiState, mirroring :app's PlaybackController's shape, trimmed to what the watch UI (step 6, not this step) will need.

Test plan

  • ./gradlew assembleDebug testDebugUnitTest lintDebug passes across :app/:core/:wear
  • New unit tests: WearPlaybackUrlResolverTest (regression guard — always enclosureUrl, never a downloaded file), WearPlaybackMediaItemFactoryTest (MediaItem construction, artwork fallback, resume position)
  • Installed and launched both debug builds — confirmed no crash on either
  • WearPlaybackController isn't called from anywhere yet — no UI exists to trigger play() until step 6 replaces the placeholder MainActivity screen, so there's nothing to manually play-test on-device in this PR

Step 5 of Wear OS phase 1: the watch can now actually stream and
play an episode from its own local (synced) queue, independent of
the phone.

- WearPlaybackUrlResolver always resolves to FeedItem.enclosureUrl --
  no downloaded-file branch, since phase 1 is streaming-only
  (regression guard for phase 2/#277's eventual file-transfer support).
- WearPlaybackMediaItemFactory builds a Media3 MediaItem from a
  FeedItem, trimmed from :app's PlaybackMediaItemFactory: no mobile-
  data gating, per-feed speed, or volume boost, since none of that
  settings state is part of what WearQueueSyncApplier syncs onto the
  watch.
- WearPlaybackService (a MediaSessionService) owns the ExoPlayer
  instance, auto-advances through the local queue on episode
  completion, and pushes its position-save loop through WearSyncClient
  the same way :app's PlaybackService does -- trimmed from it: no
  preload manager/timeline lookahead, no Android Auto browse tree.
- WearPlaybackController is a thin MediaController wrapper exposing
  WearPlaybackUiState, mirroring :app's PlaybackController's shape,
  trimmed to what the watch UI (step 6, not this step) will need.

Verified: full assembleDebug/testDebugUnitTest/lintDebug across all
three modules, installed and launched both debug builds with no
crash. WearPlaybackController isn't called from anywhere yet -- no
UI exists to trigger play() until step 6 replaces the placeholder
MainActivity screen.
@mapitman
mapitman merged commit 5a67999 into main Sep 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant