2026-08-22 07:52:54 +00:00
|
|
|
# Event Tracker — Android (v1, minimal)
|
|
|
|
|
|
|
|
|
|
Touchscreen companion to the desktop GTK app. Reads/writes the exact
|
|
|
|
|
same `event,timestamp` CSV format, so whatever syncs that file between
|
|
|
|
|
your Linux box and your phone (FolderSync, DAVx5, etc.) is all the
|
|
|
|
|
"syncing" this app needs to know about — it just reads a local file path
|
|
|
|
|
on the phone.
|
|
|
|
|
|
|
|
|
|
**v1 scope, on purpose:** record buttons, today's totals, one simple
|
|
|
|
|
bar. No stats popup, no renaming/adding events, no weekly/monthly
|
|
|
|
|
charts — that's the desktop app's job. Once this actually builds and
|
|
|
|
|
runs reliably, ask for v2 to bring those over.
|
|
|
|
|
|
|
|
|
|
**Known limitation, be aware of it:** FolderSync/DAVx5-style tools sync
|
|
|
|
|
whole files, they don't merge CSV rows. If you log an event on both
|
|
|
|
|
devices inside the same sync window, you'll likely get a conflicted
|
|
|
|
|
duplicate file instead of one merged log — sync frequently, or avoid
|
|
|
|
|
logging on both devices back-to-back.
|
|
|
|
|
|
|
|
|
|
## 1. Check what's already installed (read-only)
|
|
|
|
|
|
|
|
|
|
Run on the Linux machine you're building from (not the phone):
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
command -v buildozer && buildozer version 2>&1
|
|
|
|
|
command -v java && java -version 2>&1
|
2026-08-22 08:32:29 +00:00
|
|
|
archlinux-java status 2>&1
|
2026-08-22 07:52:54 +00:00
|
|
|
python3 -c "import cython; print('cython:', cython.__version__)" 2>&1
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 2. Install missing pieces
|
|
|
|
|
|
|
|
|
|
**Arch / EndeavourOS:**
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-08-22 08:32:29 +00:00
|
|
|
sudo pacman -S --needed jdk17-openjdk
|
2026-08-22 07:52:54 +00:00
|
|
|
```
|
|
|
|
|
|
2026-08-22 08:32:29 +00:00
|
|
|
Gradle (pulled in by buildozer/p4a) needs a JDK it actually supports —
|
|
|
|
|
`jdk-openjdk` on a rolling-release system tracks whatever's newest, and
|
|
|
|
|
a too-new JDK breaks Gradle's build-script compiler with `Unsupported
|
|
|
|
|
class file major version …`. `jdk17-openjdk` specifically, installed
|
|
|
|
|
alongside whatever your system default is (`archlinux-java status`
|
|
|
|
|
lists both — no need to switch the default). `build.sh` points this
|
|
|
|
|
build at it via `JAVA_HOME` on its own; if `archlinux-java status` shows
|
|
|
|
|
it under a different name on your machine, update
|
|
|
|
|
`JAVA_HOME_FOR_BUILD` at the top of `build.sh` to match.
|
|
|
|
|
|
2026-08-22 07:52:54 +00:00
|
|
|
buildozer and cython go in an isolated venv, not system Python — see
|
|
|
|
|
next step. (No `pip install --break-system-packages`; that pollutes the
|
|
|
|
|
system Python site-packages for no reason when a venv does the job.)
|
|
|
|
|
|
|
|
|
|
## 3. Build
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
cd android
|
|
|
|
|
./setup-build-env.sh # creates build/venv/, installs buildozer + cython into it — safe to re-run
|
|
|
|
|
./build.sh android debug
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`build.sh` is a thin wrapper that just runs buildozer through the venv,
|
|
|
|
|
so you don't have to remember to activate it each time. First run
|
|
|
|
|
downloads the Android SDK/NDK (~1-2GB) automatically and can take
|
|
|
|
|
20-40+ minutes. Expect to troubleshoot at least once — this is normal
|
|
|
|
|
for a first Android build, not a sign something's broken in this project
|
|
|
|
|
specifically. Output lands at
|
|
|
|
|
`android/bin/eventtracker-0.1-arm64-v8a-debug.apk`.
|
|
|
|
|
|
|
|
|
|
The Android SDK/NDK buildozer downloads land in `~/.buildozer`
|
|
|
|
|
regardless of the venv — that's normal, it's not Python tooling and
|
|
|
|
|
isn't meant to be isolated the same way.
|
|
|
|
|
|
|
|
|
|
## 4. Install on the phone
|
|
|
|
|
|
|
|
|
|
Copy the `.apk` over (same sync tool, USB, whatever), enable "Install
|
|
|
|
|
unknown apps" for the file manager you open it with, tap to install. No
|
|
|
|
|
Play Store, no signing required for your own sideloaded debug build.
|
|
|
|
|
|
|
|
|
|
## 5. Grant storage permission
|
|
|
|
|
|
|
|
|
|
The permission prompt on first launch only covers legacy storage access.
|
|
|
|
|
On Android 11+, you also need to manually grant broad file access, since
|
|
|
|
|
the app needs to reach whatever arbitrary folder your sync tool uses:
|
|
|
|
|
|
|
|
|
|
Settings → Apps → Event Tracker → Permissions → Files and media → Allow
|
|
|
|
|
management of all files.
|
|
|
|
|
|
|
|
|
|
(Exact wording varies by Android version/OEM.)
|
|
|
|
|
|
|
|
|
|
## 6. First launch
|
|
|
|
|
|
|
|
|
|
Tap **Settings**, enter the full path to `event_log.csv` on this device
|
|
|
|
|
— check your sync app's own configuration for its local destination
|
|
|
|
|
folder, since that's device- and setup-specific. Save. The record
|
|
|
|
|
buttons work once a valid path is set.
|
|
|
|
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
|
|
|
|
Tunables at the top of `main.py`:
|
|
|
|
|
|
|
|
|
|
| Variable | Meaning |
|
|
|
|
|
|---|---|
|
|
|
|
|
| `DEFAULT_EVENTS` | Event list — must match the desktop app's `config.json` events to line up, since this v1 has no rename/add UI yet |
|
|
|
|
|
| `COLOR_PALETTE` | Bar colors per event, cycles by index |
|
|
|
|
|
| `TIMESTAMP_FORMAT` | Must match the desktop app's format exactly — same file, same parser |
|
|
|
|
|
|
|
|
|
|
## Planned (v2)
|
|
|
|
|
|
|
|
|
|
Not built yet, decided but deferred until this v1 is confirmed working
|
|
|
|
|
on-device:
|
|
|
|
|
|
|
|
|
|
- Stats popup, event rename/add, weekly/monthly charts — same features
|
|
|
|
|
as the desktop app's Settings/Stats & Trends.
|
|
|
|
|
- **Auto-update check.** On launch, hit Forgejo's
|
|
|
|
|
`GET /api/v1/repos/{owner}/{repo}/releases/latest`, compare the tag to
|
|
|
|
|
this app's version, and if newer, download the `.apk` asset and hand
|
|
|
|
|
it to the system installer (`REQUEST_INSTALL_PACKAGES` + a FileProvider
|
|
|
|
|
+ a pyjnius-fired install intent — you still tap "Install" once,
|
|
|
|
|
Android doesn't allow a sideloaded app to silently replace itself).
|
|
|
|
|
Decided: repo/releases stay **private**, so the app ships with a
|
|
|
|
|
read-only token embedded to call the API. Acceptable for a personal,
|
|
|
|
|
single-user tool — just worth remembering the token lives inside the
|
|
|
|
|
APK if it's ever shared or the phone is lost. Use a token scoped to
|
|
|
|
|
read-only access on this repo specifically, not a general account
|
|
|
|
|
token.
|