EARHORNMUSIC UPnP · Android TV · Phones · Android Auto · GNU/Linux
Release 0.5.0

NowPlayingCarScreen.kt

Each line, with the release that last changed it.

0.5.01package dev.stave.cartemplate
2
3import androidx.car.app.CarContext
4import androidx.car.app.Screen
5import androidx.car.app.annotations.ExperimentalCarApi
6import androidx.car.app.media.model.MediaPlaybackTemplate
7import androidx.car.app.model.Action
8import androidx.car.app.model.Header
9import androidx.car.app.model.Template
10import androidx.lifecycle.DefaultLifecycleObserver
11import androidx.lifecycle.LifecycleOwner
12import androidx.lifecycle.lifecycleScope
13import kotlinx.coroutines.flow.combine
14import kotlinx.coroutines.launch
15
16/**
17 * Primary Car App screen — uses [MediaPlaybackTemplate] which lets the
18 * Auto host render album art, track metadata, and playback controls
19 * directly from the app's MediaSession. The host controls the layout
20 * — large album art, transport controls positioned by the host — so
21 * we get the optimal rendering for each head unit without fighting
22 * the template system.
23 *
24 * Header actions allow navigation to the album detail view (tap the
25 * "Album" action → push [AlbumDetailCarScreen]).
26 */
27@OptIn(ExperimentalCarApi::class)
28class NowPlayingCarScreen(
29 carContext: CarContext,
30 private val bridge: CarSessionMediaBridge,
31) : Screen(carContext) {
32
33 @Volatile private var connected: Boolean = false
34
35 init {
36 lifecycle.addObserver(object : DefaultLifecycleObserver {
37 override fun onCreate(owner: LifecycleOwner) {
38 lifecycleScope.launch {
39 bridge.isConnected.combine(bridge.currentItem) { c, _ -> c }
40 .collect { c ->
41 connected = c
42 invalidate()
43 }
44 }
45 }
46 })
47 }
48
49 override fun onGetTemplate(): Template {
50 android.util.Log.i("EarhornCar",
51 "NowPlayingCarScreen.onGetTemplate connected=$connected")
52
53 val headerBuilder = Header.Builder()
54 .setTitle("Earhorn")
55 .setStartHeaderAction(Action.APP_ICON)
56
57 // "Album" action — drill into album track listing
58 val currentItem = bridge.snapshotCurrentItem()
59 if (currentItem != null) {
60 val albumTitle = currentItem.mediaMetadata.albumTitle?.toString()
61 if (!albumTitle.isNullOrBlank()) {
62 headerBuilder.addEndHeaderAction(
63 Action.Builder()
64 .setTitle("Album")
65 .setOnClickListener {
66 screenManager.push(
67 AlbumDetailCarScreen(carContext, bridge, currentItem)
68 )
69 }
70 .build()
71 )
72 }
73 }
74
75 return MediaPlaybackTemplate.Builder()
76 .setHeader(headerBuilder.build())
77 .build()
78 }
79}