Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
48 lines
3.2 KiB
Plaintext
48 lines
3.2 KiB
Plaintext
android: the media mirror grows a queue window the card never shows
|
|
|
|
The Kotlin side of the mirror has always known about exactly one track, and
|
|
media3's `SimpleBasePlayer.getState()` — the thing an Android Auto session is
|
|
built on — wants a playlist and an index into it. So the data lands a round
|
|
before the migration that needs it, where it cannot break anything:
|
|
`NowPlaying` and `NowPlayingArgs` carry a bounded `queue` of at most
|
|
twenty-one entries, the current item and ten either side, each with its id,
|
|
title, artist, album, duration and art key, plus `queueIndex`, where the
|
|
current one sits within that window rather than within the whole queue.
|
|
`src/mobile/media.svelte.js` fills them from `player.queue` and `player.qi`;
|
|
`MediaService` ignores every bit of it, so the card is byte for byte the card
|
|
it was. Ten either side because one covers the card's own prev and next and
|
|
nothing else while a queue list — which is what Auto asks for — wants a
|
|
screenful plus a scroll both ways, and it is a cap rather than a length: a
|
|
two-thousand-track queue crosses the bridge as twenty-one entries exactly
|
|
like a twenty-one-track one, measured at two kilobytes of JSON for twenty-one
|
|
short titles and six with long ones and real cover paths, against the thirty
|
|
to eighty of base64 cover that already ride the same call once per record.
|
|
|
|
Nothing renders it, which is the whole difficulty in checking it — and both
|
|
hops of this bridge fail silently, because serde drops an unknown field and
|
|
tauri's Jackson mapper has `FAIL_ON_UNKNOWN_PROPERTIES` off, so a key spelled
|
|
snake_case where camelCase was wanted arrives as nothing at all with no error
|
|
anywhere. `MediaSessionPlugin.update` logs one line per update, and the phone
|
|
walk holds that line against `__ss.card` — the mirror media.svelte.js now
|
|
keeps of what it last sent, the shape xfernote has kept of the shade since it
|
|
was written — field for field, through a next and a previous. The art-key
|
|
count is compared as well as the size and the index, since that is the only
|
|
camelCase field an entry has. The check arms at queue index one rather than
|
|
at wherever the walk left off, which buys a row on either side — `prev()`
|
|
seeks to zero at the top of a queue and `next()` stops at the end — a track
|
|
that has only just started, so `prev()` is still a step rather than the seek
|
|
it becomes past five seconds, and a window whose own index is the queue
|
|
index, because nothing is clamped off the front while the index is under ten.
|
|
Each of the three readings has to be a fresh one at both ends, the push
|
|
counter up and a new line in the log, since a `prev()` that lands back where
|
|
it started reads exactly like a stale line otherwise; and a queue too short
|
|
to arm, or repeat-one, under which `next()` seeks instead of stepping, fails
|
|
the check rather than skipping it.
|
|
|
|
The plugin's `consumer-rules.pro` keeps the new `@InvokeArg` class by name
|
|
beside the one it already keeps; without that line a release build would fill
|
|
`NowPlayingArgs` and leave every queue entry null, quietly. Rust and Kotlin
|
|
both changed, so this one cannot go down `dev.sh` — it needs the full
|
|
`deploy.sh` detour. And everything the walk already asserts about the card is
|
|
untouched, which is the real check on this round.
|