v0.19.0: andTunes plays music on the Rabbit
The Android half of andTunes had been paused on a 1 GB toolchain download (Gradle wrapper, Android Gradle Plugin, Kotlin). None of that was needed: platform 33 and build-tools 34 were already in ~/Android/Sdk, and an app that links no libraries needs five SDK steps, not a build system. andtunes/build.py runs aapt2 -> javac -> R8 -> zipalign -> apksigner and produces a 61 KiB APK. andTunes 0.1.0 is framework-only Java: a six-tile menu that loads nothing, a streaming library.json parse grouped into artists and albums in one pass, one ListActivity for every list (songs and artist songs open with Shuffle all, albums carry art thumbs, search as you type), a Now playing bar under every list, and a white Now Playing screen with square art, a slim scrubber, prev/play/next, shuffle and repeat, and no back button. A foreground PlaybackService owns the queue: audio focus, becoming-noisy, MediaSession and a MediaStyle notification, end of queue pauses, missing files skip, and the last queue and position come back on launch. Black on white, and every size doubled for the R1's override density. Cold start to the menu: 313-338 ms. The scroll wheel turned out to be DPAD_UP/DOWN (stock Generic.kl), not volume. The app takes both in dispatchKeyEvent: lists scroll a row per detent, and the menu and Now Playing get volume. LinTunes side: Connections > Install andTunes on Rabbit... installs the committed APK over adb and grants all-files access, or copies it to Download/ over MTP when there's no adb. Sync fills Buttons/ with default artwork only where a file is missing, so trav's own art is never overwritten. Verified against the dev library only, synced to the R1 and driven with adb input + screencap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KSsYtRn4WZx6xj4GEdVPt9
This commit is contained in:
@@ -1,5 +1,60 @@
|
||||
## Done
|
||||
|
||||
### Round 50 (2026-09-11) — andTunes plays music on the Rabbit (v0.19.0)
|
||||
|
||||
The Android half of andTunes had been paused on a 1 GB toolchain download.
|
||||
It turned out not to need one.
|
||||
|
||||
- [x] **No Gradle, no Kotlin, no download.** Platform 33 + build-tools 34 were
|
||||
already in `~/Android/Sdk`, and an app that links nothing needs five SDK
|
||||
steps, not a build system. `andtunes/build.py` runs aapt2 → javac → R8
|
||||
→ zipalign → apksigner. The APK is 61 KiB. trav's call, after asking
|
||||
what Kotlin and Gradle even buy: nothing the app needs.
|
||||
- [x] **andTunes 0.1.0, framework-only Java** (`andtunes/app/`):
|
||||
- a six-tile menu that loads nothing
|
||||
- a streaming `library.json` parse on a background thread, grouped into
|
||||
artists and albums in one pass
|
||||
- one `ListActivity` for playlists, artists (→ All songs + albums with
|
||||
art thumbs), albums, songs (Shuffle all first) and search
|
||||
- a Now playing bar on every list, with the playing song drawn inverted
|
||||
- Now Playing: white, square art, slim scrubber, ◀ ⏯ ▶, shuffle, repeat
|
||||
off/all/one, **no back button**
|
||||
- a foreground `PlaybackService` with audio focus, becoming-noisy,
|
||||
MediaSession and a MediaStyle notification
|
||||
- end of queue pauses, missing files skip with a toast, and the last
|
||||
queue and position come back on launch
|
||||
Black on white throughout for the dim panel, and every size doubled
|
||||
for the R1's override density.
|
||||
- [x] **Cold start 313–338 ms** to the menu, measured with `am start -W` on
|
||||
the R1 (target < 400; the first launch after install is 551 ms,
|
||||
because of dex verification).
|
||||
- [x] **The scroll wheel is DPAD, not volume.** `dumpsys input` shows
|
||||
`och1970_holl_key` uses the stock `Generic.kl` (KEY_UP/DOWN →
|
||||
DPAD_UP/DOWN). The app takes both DPAD and VOLUME codes in
|
||||
`dispatchKeyEvent`, down and up. Lists scroll a row per detent; the
|
||||
menu and Now Playing get volume.
|
||||
- [x] **Replaceable buttons.** `andtunes/tools/make_buttons.py` renders the
|
||||
defaults (menu tiles + ◀ ▶ ⏯). Sync copies them into the device's
|
||||
`Buttons/` **only where the file is missing**, and the app prefers
|
||||
whatever is there.
|
||||
- [x] **Connections ▸ Install andTunes on Rabbit…** (`lintunes/andtunes/
|
||||
install.py`): adb install -r, then the all-files and notification
|
||||
grants. The prompt says Install / Update / Reinstall based on the
|
||||
version already on the device. With no adb, it copies the APK to
|
||||
`Download/` over MTP. The APK is committed in `lintunes/android/` and
|
||||
ships with the self-updater.
|
||||
- [x] **The R1 now comes up as `mtp,adb`** whenever it's unlocked
|
||||
(`svc usb setScreenUnlockedFunctions mtp`), so sync's gvfs mount and
|
||||
adb are both there with no mode switching.
|
||||
- [x] Found while building: R8 8.2 dies with an internal NPE on javac 21's
|
||||
debug attributes for an anonymous class, so `proguard.pro` keeps none.
|
||||
- [x] Verified with the **dev library** only: synced headless to the real
|
||||
gvfs mount (21 tracks, 5 playlists, 4 covers). Then driven on the R1
|
||||
with `input tap`/`keyevent` + `screencap` through menu → songs → shuffle
|
||||
→ now playing, artists → artist → album thumbs, the wheel, search, and
|
||||
resume after a force-stop. `tests/test_round50.py` covers button
|
||||
shipping and the installer; the full suite passes.
|
||||
|
||||
### Round 49 (2026-09-10) — Import from URL (v0.18.0)
|
||||
|
||||
trav's `song` shell helper is `yt-dlp --extract-audio --audio-format mp3`,
|
||||
|
||||
Reference in New Issue
Block a user