Repository navigation
v0.1.1 (debug build)
Pre-release
Pre-release
Second sideloadable build (debug-signed APK; enable "install from unknown sources"). Everything below is a change since v0.1. Verified on one Xiaomi/HyperOS device (Android 16) plus 41 JVM unit tests and clean lint. Gestures, the file-picker screens and HyperOS Island display were not machine-testable (MIUI blocks injected input) and still need hands-on checking.
Fixes: playback and queue
- Media playback works. Root cause of "unable to play any media": the playback service granted empty command sets to the UI, so every play/load command was silently denied. Commands are now granted explicitly. Also fixed: the controller being released right after connecting, and a launch crash caused by a missing notification-button icon.
- Real playlist queue. The player now owns the whole queue, so next / previous / auto-advance to the next track work. Previously only one item was ever loaded, so the notification had no Next button and tracks never advanced.
- Notification controls: Previous, Play/Pause, Next, and a Pause/Resume timer button. The timer button label now stays in sync when you toggle the timer from the screen (it used to go stale).
- Survives UI recreation (dark mode, font size, language change): the UI re-syncs from the player instead of showing "no media" over playing audio.
- Unplayable files are skipped. A deleted/moved/unreadable file shows "Can't play this file" and moves on instead of leaving a black screen.
- Tapping play/pause after a track ends restarts it (was a no-op).
Gym-use improvements
- Screen stays on while the app is open.
- Audio focus (calls and other apps pause playback), pauses when headphones are unplugged, and a wake lock so local playback doesn't stutter with the screen off (new
WAKE_LOCKpermission). - Timer survives the app being killed (HyperOS kills background apps aggressively). A running timer is resumed with the time that passed; if it was saved more than 12 hours ago it is restored paused instead.
Bug fixes found by testing
- Timer digits used the phone's locale, so Arabic-locale phones would show Arabic-Indic digits. Now always
00:00:00Latin digits. - Negative values formatted as garbage; negative countdown targets are clamped to zero.
- Playlist saving is now atomic (a crash mid-save could have wiped all playlists); a corrupt playlist file is kept as
playlists.json.corruptinstead of being overwritten. - Picking files from a provider that refuses persistent access no longer crashes the app.
- Deleting a playlist releases file permissions no other playlist uses (Android caps how many an app can hold).
- Huge embedded cover art could crash the app with out-of-memory; it is now decoded at a bounded size.
- Lint errors fixed (wrong error constant for unsupported custom commands, missing opt-in markers).
Performance
- Timer text updates once per displayed second and is drawn without recomposing the whole screen (was 10 recompositions/second).
- Equalizer animates only while media is playing, and animates without per-frame layout.
- Ambient background colour is sampled from a 128px frame instead of a full-size video frame (a 4K frame is ~33 MB).
- Drag-to-scrub seeks are throttled to ~10/second (the last position is always applied).
- The gesture handler no longer restarts on unrelated state changes (which cancelled in-flight gestures and forgot a pending double-tap).
- Measured on device: p50 11 ms, p99 15 ms frame time during video + timer.
Security
- The media service is exported so system UI and Bluetooth can reach it, but it previously accepted any app as a controller. It now only accepts this app, the system media notification, and system-trusted controllers.
- The debug launch hooks (
debug_media_uris,debug_timer_start) only work in debuggable builds, so other apps cannot inject media through the exported activity. allowBackupdisabled so playlist data isn't included in device backups.
Tests and tooling
- 41 JVM unit tests (timer engine, snapshot/restore, tick scheduling, scrub throttling, playlist storage, image sample sizing); lint clean; clean debug and release builds. Logs are in
test-logs/.
Known limitations
- Debug-signed: fine for your own phone, not for Play Store. Updates install over v0.1 only if signed with the same debug key (same build machine); otherwise uninstall first.
- A countdown that finishes while the app is in the background is only noticed when you return (no background alarm yet).
- The equalizer is a decorative animation, not audio-reactive (that would need the microphone permission).
- Android limits persisted file permissions per app; the app doesn't warn you when you approach the limit.
- Not verified: gesture behaviour after these changes, the file-picker screens, headphone-unplug pause, and whether HyperOS shows the notification in the Island.
Full diff: v0.1...v0.1.1