:core:playback
August 15, 2026 · View on GitHub
Purpose
Owns playback session control, queue orchestration, smart queue logic, Media3 playback services, the offline download foreground service, and Android Auto browse/collage support. It does not own Room schemas, preference storage, RSS parsing, ranking persistence, smart-download workers, or feature UI.
Public API
PlaybackRepositoryexposes player/session operations to app and feature UI (history ports via class delegation toPlaybackHistoryStore; queue / transport / sleep / history helpers via same-package extension API files).isTransportReady()reports whether a Media3 controller is connected; the transport API also exposes previous/next and seek (skip forward/back) operations used by the home-screen widget adapter.QueueRepositoryandQueueManagerpersist and orchestrate explicit queue operations.QueueManageremitsqueue_modifiedadd only afterPlaybackRepository.addToQueuereturns success.PlaybackQueueCoordinatoremitsqueue_modifiedremove on remove;undoQueueRemovalemits a compensatingadd(source=undo) so undone removals do not permanently skew analytics.QueueMath,QueueSkipMemory,SmartQueueEngine,SmartQueueSources, andMixtapeEngineimplement queue and mixtape logic.DefaultSmartQueueSourcesreads a boundedgetEpisodeWindow(~200, around the current episode for same-show continuation) — nevergetAllNewestof a mega-feed. Ready local catalogs serve Room pages; not-ready PI shows still union cached extras.PlaybackMediaIdPolicy,PlaybackArtworkResolver, andPlaybackSkipPolicydefine session IDs, artwork, and skip behavior.PlaybackMediaIdPolicy.customCacheKey(via:core:modelEpisodeMediaCacheKey) appends briefing audiov=so Media3 does not keep playing a same-day regenerated brief from a stale SimpleCache entry.PlaybackSkipPolicyalso owns intent-aware stale resume: when Settings → Playback → Restart forgotten episodes is on (default), implicit plays (queue / mixtape / Smart Queue / casual) soft-expire mid-episode seek after 7 days withoutlastPlayedAt; Jump Back In (home_hero_resume*) and History (library_history) always seek. Progress is never wiped — seek policy only. Mixtape/SQ still select unfinished episodes within the 30-day suggestion band; chrome follows soft-expire (mixtape hides progress / “Xm left”; Smart Queue stampsresume_stale→ queue label “Starting over”).PlaybackControlSynckeeps UI playback speed / seek sizes aligned with Media3 when a session is cleared or a new queue starts, and sanitizes user-requested speeds before apply/persist.HistoryRecommendationLogic,AutoVoiceSearchLogic,SmartQueueRefillPolicy,MixtapeResumePolicy,PlaybackEntryPointResolve,NightWindowLogic, andListeningHistoryUpsertLogicare JVM-testable playback helpers.PlaybackEntryPointResolvemaps fine-grained source-contextentry_pointstrings (home_mixtape,learn/learn_history,briefing) to coarsePlaybackEntryPointfor queue/mixtape policy while the raw string still attributesplayback_*.AutoArtworkFetchLogicandAutoCollageFreshnessLogicencode Android Auto artwork fetch / collage cache policy for hermetic tests.AutoCollagePrewarmPolicyandAutoCollageFolderLogicencode prewarm throttle and aligned image/key folder inputs for hermetic tests.PlaybackIntroOutroControllermanages intro-skip and outro-trim playback lifecycle.service.BoxLorePlaybackService,service.MediaDownloadService, andservice.AutoCollageProviderare manifest-facing services.service.SmartQueueRefillCoordinator,service.CoilBitmapLoader, andservice.auto.*support service internals and Android Auto.- Android Auto browse artwork:
AutoArtworkRepository+AutoArtworkSourceStoreregister remote/local sources into an in-memory map immediately andcommitprefs on a background thread before/while returningcontent://…/art|local|collage/…URIs.AutoCollageProviderlazily fetches remote covers with validated HTTPS redirects, lenient image content-types, magic-byte checks, and one retry; folder collage URIs include av=cache-buster so Auto hosts reload when resume/history content changes.AutoCollagePrewarmer/AutoCollageGenerator/AutoCollageLayoutsrebuild section collages from content keys (resume episode IDs, queue IDs, subscriptions, …), use a shorter TTL for partial/fallback tiles, and refresh on mark-complete / queue changes viaAutoBrowseLibraryHost.requestAutoCollageRefresh. MIX/RESUME badge labels prefer app-merged Google Sans Flex with lettering roundness fromboxlore_theme_fast_cachevia:core:prefsFontRoundnessAxis(no:core:designsystemdependency).AutoArtworkDownloaderis the shared HTTPS fetch path (validated redirects + public-host checks) used by both collage generation and the ContentProvider.
Internal structure
src/main/java/cx/aswin/boxlore/core/playback/
PlaybackRepository.kt # session core; delegates ListeningHistory* ports
PlaybackHistoryStore.kt # history ports only; implements history ports
PlaybackHistoryStoreApi.kt # non-port history helpers (extensions)
PlaybackHistoryMappings.kt # history entity ↔ model mappers
PlaybackHistoryDeps.kt # player + data deps for HistoryStore ctors
PlaybackSleepController.kt # sleep timer + late-night nudge
PlaybackRepositoryQueueApi.kt # queue extension API
PlaybackRepositoryTransportApi.kt # transport / seek / speed extension API (+ [isTransportReady])
PlaybackRepositoryHistoryApi.kt # non-port history extension API
PlaybackRepositorySleepApi.kt # sleep / nudge extension API
PlaybackRepositoryChaptersApi.kt # chapters / transcript extension API
QueueManager.kt
QueueRepository.kt
...
service/
BoxLorePlaybackService.kt
MediaDownloadService.kt
AutoCollageProvider.kt
SmartQueueRefillCoordinator.kt
auto/
src/main/java/cx/aswin/boxlore/core/data/service/
AutoCollageProvider.kt
BoxLorePlaybackService.kt
MediaDownloadService.kt
PlaybackRepository implements ListeningHistoryPort / ListeningHistoryBackupPort via Kotlin
class delegation to PlaybackHistoryStore. Same-package extension files expose the remaining
public one-liner API (playQueue, toggleLike, setSleepTimer, …) so the repository class
stays under detekt LargeClass / TooManyFunctions limits.
Files under core/data/service are compatibility stubs for old service class names.
Dependencies
- Project dependencies:
:core:model,:core:network,:core:database,:core:catalog,:core:downloads,:core:ranking,:core:analytics, and:core:prefs. - Libraries: Media3 ExoPlayer, Media3 Session, Media3 UI, Coil, Palette, Gson, OkHttp, coroutines, and AndroidX core.
- Reverse-edge rule: catalog and downloads must not depend back on playback. Downloads launch
MediaDownloadServicethrough the app-installed launcher port.
Threading / lifecycle
PlaybackRepository,QueueRepository, andQueueManagerare application-scoped throughAppContainer.BoxLorePlaybackServiceis a Media3MediaLibraryServiceand resolves shared dependencies lazily after application startup.- Player callbacks run on the main thread; database, artwork, and recommendation work use coroutine scopes and background dispatchers.
Persistence & identity
- Manifest-facing service class names are system identities.
- Media ID prefixes such as
episode:,queue:, andlearn:are session and Android Auto contracts. - SharedPreferences file
boxcast_playerstores playback session flags. - SharedPreferences file
android_auto_artwork_sourcesmaps Android Auto artwork content keys to remote HTTPS URLs or sandboxed local paths (identity for Auto collage ContentProvider; do not rename lightly). - Preference key
device_uuidis a stable install identifier and must not be logged raw. - Queue, history, and download rows are persisted by
:core:databaseand:core:downloads.
Testing notes
- Unit tests live under
core/playback/src/test. - Existing coverage includes skip policy (including stale-resume intent × flag × freshness), media ID policy, artwork resolution, control sync (speed/seek preserve on clear), history recommendation filtering, voice search, smart-queue refill policy, mixtape resume policy, night-window logic, listening-history upsert logic, queue math, skip memory, smart queue (including feed-supplement merge + negative-id continuation), playback session mapping, Auto artwork fetch/content-type policy, collage freshness signatures, and Auto artwork source-store durability.
- Service-level tests must install shared dependency holders before exercising service code.
./gradlew :core:playback:testDebugUnitTest
CI relevance
unit-tests.ymlruns playback JVM tests.- Service and Android Auto behavior are primarily validated by app assembly, emulator/device smoke, and manual checks.
- Dependency guard tracks release runtime dependencies for this module.