KeelrLeek 4d75395411 android auto: the car's own controls, the covers, and four tabs with faces
Everything here came from putting the thing on a real head unit and looking at
it, which is the only reason any of it was found.

**The transport did nothing.** Pause, seek, next and previous all routed
through `MediaHub.act`, which is a round trip out to the WebView — and a car
that started a cold process has no WebView, so every button drew, moved, and
sent a message to nobody. `AutoNative.driving()` reports whether the headless
queue is what is playing, and when it is, the transport goes straight to the
engine instead: pause/resume, a real seek, and next/previous that move the
fallback queue and push a card update after them. A normal phone session is
untouched and still goes through the JS, which owns shuffle, repeat, `alts`
failover and the real queue.

That is the THIRD instance of one bug: the headless path silently skipping
something the WebView path does for free. Audio focus was the first (a live
AAudio track, muted, audible to nobody), the card was the second (STATE_NONE
over playing music), the transport is this one. Anything the JS does on the
way to making a sound has to have an answer here too, and the failure is always
silence rather than an error.

**The covers, and the colour.** The playback screen was showing the app icon,
because nothing filled the card's art. Android Auto washes that screen with a
colour it extracts from whatever artwork it is handed — so every record was
tinted the falcon's blue. The engine already knows the album's cover path, so
it now travels with the track and the card is built from it. Random Access
Memories comes up gold. The app derives an accent per cover and the car cannot
be told to, but it turns out the car does it anyway, for free, given art.

**Four tabs with icons**, which is what every other media app in the car has:
a root browsable item's artwork is drawn as its tab icon, and ours had none, so
they rendered as bare words. `android.resource://` URIs rather than the
FileProvider — these are our own resources, identical on every install, and
granting a per-connection URI for an icon that never changes would be wrong.

**The grid, in the right place.** The hint was set on each node's own
`LibraryParams` when returning its children; Auto reads it from the ROOT as a
default and from the PARENT ITEM as an override. So the albums drew as a list
with the grid hint set correctly and delivered nowhere. The root declares
`CONTENT_STYLE_SUPPORTED` now and the `ss:albums` tab carries the override,
along with each artist, whose children are also sleeves.

**Shuffle** is a `CommandButton` on `setMediaButtonPreferences` — both spellings
exist in 1.10.1 and `setCustomLayout` is the older one. It uses the PREDEFINED
`ICON_SHUFFLE_ON` rather than a drawable of ours: a custom resource the host
does not recognise is dropped silently, which is what happened the first time,
and `ICON_SHUFFLE_OFF` names the state and is drawn as a circular arrow that
reads as repeat. It reorders only what is AHEAD, so the current song does not
restart under the driver's hands and "previous" still goes back to what was
actually heard.

The accent is `#31C0CB` in a car theme named by
`com.google.android.gms.car.application.theme`. Its parent is a FRAMEWORK theme
because the style is resolved inside the car's process, where AppCompat and
Material are not guaranteed to exist.

Proven on the Pixel 6a through a real Android Auto session, driven from the
DHU: the four tabs render with their icons, Albums is a grid of full covers,
the playback screen shows the album art with the colour pulled from it, and a
media `next` moves the queue and lands the card on "The Game of Love".

**What this does not touch, and it is the next question.** Everything in the
tree is a local file. Playlists are in the database, are local, and would play
from cold exactly as albums do — they are absent only because Auto gives four
root slots and four are taken, which is a trade to make rather than a limit.
Catalog and Soulseek rows genuinely cannot play from a cold process, but they
CAN whenever the app is warm, through the same `MediaHub.act` round trip the
transport just stopped depending on — browsable always, honest error only when
there is no WebView. That is a better answer than the design's "never" and it
is where this goes next.
2026-09-15 13:30:54 -05:00
2026-09-10 07:19:18 -05:00
S
Description
SoulSeek Streaming app.
9.5 MiB
1 Stars 2 Watchers 1 Forks
Languages
Rust 48.3%
Svelte 38.1%
JavaScript 13.4%
CSS 0.2%