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

EarhornCarAppService.kt

package dev.stave.cartemplate

import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.validation.HostValidator

/**
 * Car App Library entry point. Declared in AndroidManifest.xml under the
 *   <action android:name="androidx.car.app.CarAppService" />
 *   <category android:name="androidx.car.app.category.MEDIA" />
 * intent filter, which is what makes Auto's launcher offer a custom UI
 * instead of falling back to the MediaLibraryService template.
 *
 * The actual UI lives in [EarhornCarSession] and the [androidx.car.app.Screen]
 * subclasses it pushes onto the ScreenManager stack. This service is just
 * the lifecycle anchor that Auto binds to.
 *
 * Coexistence: the existing [dev.stave.playback.PlaybackService] is also
 * declared as a media-browser-compatible service. Auto picks whichever
 * surface the host supports; on hosts that support the Car App Library
 * MEDIA category, this service wins. Older hosts continue to use
 * PlaybackService's MediaLibrarySession unchanged.
 *
 * No Hilt injection here — the only dependency we need is the
 * application Context (for the MediaController bind), which Service
 * provides natively. Keeping this Hilt-free avoids the need to modify
 * any existing DI graph.
 */
class EarhornCarAppService : CarAppService() {

    override fun onCreate() {
        super.onCreate()
        android.util.Log.i("EarhornCar", "╔══ EarhornCarAppService.onCreate ══╗")
    }

    // Only Google's car hosts may bind (design decision 2026-09-02, I.76).
    // ALLOW_ALL_HOSTS_VALIDATOR let any app on the phone act as the car.
    override fun createHostValidator(): HostValidator =
        HostValidator.Builder(applicationContext)
            .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample)
            .build()

    override fun onCreateSession(): Session {
        android.util.Log.i("EarhornCar", "╠══ onCreateSession — Auto host bound ══╣")
        return EarhornCarSession()
    }
}