moved tasks to projects board

This commit is contained in:
2026-09-28 19:37:11 -07:00
parent 720f5c10a2
commit da9186420b
7 changed files with 125 additions and 2022 deletions
+28
View File
@@ -0,0 +1,28 @@
# andTunes — device facts
Measured facts about the Rabbit R1 that the app is built around.
(Moved out of the old andtunes/TASKS.md board on 2026-09-24.)
- Panel **480 × 640 px**, physical density 320, **override density 160** — so
the app sees a 480 × 640 **dp** canvas on a 2.88" screen (~278 real ppi).
- **One dp is about half its usual physical size here.** Double every stock
value: body text 28–32 sp, list rows ≥ 88 dp, menu tiles ~213 dp. A 48 dp
row would be 4.4 mm tall. Do not "fix" this by changing the device density —
trav likes it where it is.
- Android 13 / API 33, `gsi_r1-userdebug`, arm64-v8a, 65 GB free.
- **The wheel can only ever give us detents.** `getevent -pl` (2026-09-14):
`och1970_holl_key` advertises `KEY (0001): KEY_UP KEY_DOWN` and *nothing
else* — no `EV_REL`/`REL_WHEEL`, no `EV_ABS`, no resolution. The `och1970`
is a Hall latch, so the driver quantises the magnet into clicks and hands
userspace one key press each. There is no sub-detent position to read
without a kernel driver change, so every bit of nuance has to be derived
from the *timing* between detents (see `WheelScroll`).
- Scroll wheel = input device `och1970_holl_key` → **KEY_UP / KEY_DOWN**,
mapped by the stock `Generic.kl` (checked 2026-09-11 via `dumpsys input`)
to **`KEYCODE_DPAD_UP` / `DPAD_DOWN`** — not volume. Side/PTT button sits
on `mtk-kpd` with KEY_VOLUMEDOWN + KEY_POWER. Headset exposes
KEY_PLAYPAUSE, so a MediaSession gets media keys for free.
- USB: set to come up as **`mtp,adb`** whenever the screen is unlocked
(`adb shell svc usb setScreenUnlockedFunctions mtp`, 2026-09-11), so the
gvfs mount sync uses and the adb install uses are both there at once.
+2 -2
View File
@@ -209,6 +209,6 @@ push onto any Android device or emulator with `adb push`. That tree includes
the awkward cases on purpose — an emoji album name, a 208-character title, two
tracks that differ only by id, a track with no artist.
## Board
## Device facts
`TASKS.md` in this directory.
`DEVICE.md` in this directory: screen density, wheel keycodes, USB modes.
-120
View File
@@ -1,120 +0,0 @@
# andTunes — task board
A music player for the Rabbit R1 that never scans anything: LinTunes writes
`Music/andTunes/library.json` during sync and the app just reads it. See
`../andTunes spec.txt` for the original brief.
Legend: `[ ]` todo · `[~]` in progress · `[x]` done.
**Status: phases 1–3 done (2026-09-11, LinTunes rounds 50–51, andTunes
0.2.0); 0.2.1 (LinTunes round 54, 2026-09-14) fixed the grouping crash —
`Library.group()` keyed albums case-folded but artists raw-case, so one artist
spelled two ways on one album ("RJD2" / "Rjd2") took the whole library down
with `Couldn't read library.json`. Both maps fold case now, and `Artist` has a
`key` the way `Album` always did. 0.2.2 (round 55, 2026-09-14) reversed the
wheel in lists and made it scroll smoothly (`WheelScroll` — a pixel debt paid
off per frame, not a row per detent); volume on the other screens is
unchanged.** What's left is the *Parked* list, pulled in
as trav finds he needs it. Built with
`python3 andtunes/build.py` — plain Java, no Gradle, nothing downloaded (see
`README.md`, *Toolchain*). Phases are andTunes' own; which LinTunes round
each lands in is decided when it starts.
## Device facts (measured 2026-09-06, `adb shell wm size` etc.)
- Panel **480 × 640 px**, physical density 320, **override density 160** — so
the app sees a 480 × 640 **dp** canvas on a 2.88" screen (~278 real ppi).
- **One dp is about half its usual physical size here.** Double every stock
value: body text 28–32 sp, list rows ≥ 88 dp, menu tiles ~213 dp. A 48 dp
row would be 4.4 mm tall. Do not "fix" this by changing the device density —
trav likes it where it is.
- Android 13 / API 33, `gsi_r1-userdebug`, arm64-v8a, 65 GB free.
- **The wheel can only ever give us detents.** `getevent -pl` (2026-09-14):
`och1970_holl_key` advertises `KEY (0001): KEY_UP KEY_DOWN` and *nothing
else* — no `EV_REL`/`REL_WHEEL`, no `EV_ABS`, no resolution. The `och1970`
is a Hall latch, so the driver quantises the magnet into clicks and hands
userspace one key press each. There is no sub-detent position to read
without a kernel driver change, so every bit of nuance has to be derived
from the *timing* between detents (see `WheelScroll`).
- Scroll wheel = input device `och1970_holl_key` → **KEY_UP / KEY_DOWN**,
mapped by the stock `Generic.kl` (checked 2026-09-11 via `dumpsys input`)
to **`KEYCODE_DPAD_UP` / `DPAD_DOWN`** — not volume. Side/PTT button sits
on `mtk-kpd` with KEY_VOLUMEDOWN + KEY_POWER. Headset exposes
KEY_PLAYPAUSE, so a MediaSession gets media keys for free.
- USB: set to come up as **`mtp,adb`** whenever the screen is unlocked
(`adb shell svc usb setScreenUnlockedFunctions mtp`, 2026-09-11), so the
gvfs mount sync uses and the adb install uses are both there at once.
## Phase 1 — plays a song (v0.1.0) ✔
- [x] `java-21-openjdk-devel` — installed, `javac` on PATH. (Java 25 is also
present; `build.py` points at 21.)
- [x] Android SDK: platform 33 + build-tools 34.0.0 were already in
`~/Android/Sdk`. **No Gradle, no Kotlin** — `build.py` runs aapt2 →
javac → R8 → zipalign → apksigner directly (trav, 2026-09-11: don't
pull a GB over cell if it isn't needed; it isn't).
- [x] Project, package `me.teafry.andtunes`, minSdk 26 / targetSdk 33,
framework only: `Activity`, `ListView`, `MediaPlayer`, `MediaSession`,
`Notification.MediaStyle`, R8. The APK is 61 KiB.
- [x] `MANAGE_EXTERNAL_STORAGE` + a first-run screen that sends the user to
the toggle (LinTunes' installer grants it over adb, so it rarely shows).
- [x] Library loader: `android.util.JsonReader` streaming parse off the main
thread into a process singleton; artists/albums grouped in one pass;
an unknown `format` gets a readable message; reloads when
`library.json` changes (a re-sync) the next time the menu resumes.
- [x] `MenuActivity`: six tiles, 2 × 3, **loads nothing**. The sixth reads
"Now Playing" or "Shuffle All" depending on the service.
- [x] `ListActivity` in songs mode + "Shuffle all" header row.
- [x] `PlaybackService` (foreground) + `NowPlayingActivity`: white
background, square art, slim scrubber, ◀ ⏯ ▶, shuffle, repeat.
**No back button.**
- [x] Audio focus, ACTION_AUDIO_BECOMING_NOISY, MediaSession + notification.
- [x] End of queue **pauses** unless repeat is on. Repeat: off / all / one.
- [x] `adb shell am start -W`: **313–338 ms** cold to the menu (551 ms on the
very first launch after install, which includes dex verification).
## Phase 2 — the rest of the screens ✔
- [x] Playlists, artists (→ "All songs" + albums; all songs has its own
shuffle), albums, search (artists, albums and songs as you type).
- [x] Album art thumbs in album rows, full art on now playing.
- [x] The "Now playing" bar at the bottom of every list screen; the playing
song is drawn inverted in any list it appears in.
- [x] Scroll wheel → list scrolling (one row per detent), volume on the menu
and now-playing screens. Taken in `dispatchKeyEvent`, DPAD *and*
VOLUME codes, down *and* up, so the search box can't swallow it.
- [x] Replaceable button images: `Buttons/<name>.png` beats the bundled
drawable, for the six menu tiles plus ◀ ▶ ⏯. LinTunes ships the
defaults into `Buttons/` only where the file is missing.
- [x] Missing file (synced then deleted) skips with a toast, doesn't stop
the queue.
- [x] Resume last queue + track + position on launch (paused).
## Phase 3 — install from LinTunes, counts coming back
- [x] `Connections → Install andTunes on Rabbit…` (LinTunes 0.19.0):
`adb install -r` + the two permission grants; says Install / Update /
Reinstall from the version on the device; with no adb, copies the APK
to `Download/` over MTP for a manual tap. APK committed at
`lintunes/android/andTunes.apk` (+ `andTunes.json`, its version).
- [x] Format gate (LinTunes 0.20.0): sync reuses
`export/web_support.conversion_for` outright, because Android's
MediaPlayer decodes the same set a browser does. Protected AAC is
refused and reported; ALAC, AIFF and anything else unplayable becomes
**FLAC** (never a lossy re-encode). Conversions are cached per track, so
they're converted once and size-diffed after that.
- [x] Play counts back (andTunes 0.2.0): a natural finish counts a play, as
it does in LinTunes. The app keeps `plays/andtunes-<install id>.json` in
the per-machine-totals shape of `storage/play_journal.py`. Sync folds it
into `<data_dir>/plays/` with the per-track max *before* copying
anything, so the R1 is one more machine in the Round 38 model and there
are no new merge rules.
- [x] Retired `Sync Playlist to Rabbit (Auxio)` from the menu. (trav's R1
has no old `Music/<Playlist>/` folders, so no cleanup was needed.)
## Parked
- Gapless, crossfade, EQ, ratings, folder browsing, sleep timer, Android Auto.
- Deleting the old per-playlist folders automatically. They're outside the
andTunes root and the containment guard makes them unreachable on purpose;
removing them should be an explicit, separately-confirmed action.