NowPlayingCarScreen.kt
79 lines · 2.8 KB
Changed in: 0.5.0
| 1 | package dev.stave.cartemplate |
| 2 | |
| 3 | import androidx.car.app.CarContext |
| 4 | import androidx.car.app.Screen |
| 5 | import androidx.car.app.annotations.ExperimentalCarApi |
| 6 | import androidx.car.app.media.model.MediaPlaybackTemplate |
| 7 | import androidx.car.app.model.Action |
| 8 | import androidx.car.app.model.Header |
| 9 | import androidx.car.app.model.Template |
| 10 | import androidx.lifecycle.DefaultLifecycleObserver |
| 11 | import androidx.lifecycle.LifecycleOwner |
| 12 | import androidx.lifecycle.lifecycleScope |
| 13 | import kotlinx.coroutines.flow.combine |
| 14 | import 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) |
| 28 | class 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 | } |


