Commit Graph
3 Commits
Author SHA1 Message Date
timka123andClaude Opus 5 535830bacc android: two reasons the Glyph stayed dark
Both silent, and each alone was enough to leave the matrix blank while
everything else in the app worked.

**1. `setAppMatrixFrame` does nothing on this firmware.** The developer kit is
explicit that app-driven control must use the `App` variants, so that is what
the first cut used. On Phone (3) build 2608141733 the call is accepted without
an exception and then dropped: it forwards to `IGlyphService.setAppMatrixColors`
and the system service never reaches the hardware. Measured over 20 seconds of
1 Hz pushes: `setAppMatrixFrame` produced 0 writes to the matrix light,
`setMatrixFrame` produced 232. Both paths now use the plain variant. The kit's
warning that it can fight a selected Glyph Toy is real, but a rear display that
never lights is the worse failure.

**2. `getDeviceMatrixLength()` returns the side, not the dot count.** The name
invites the opposite reading, and the SDK settles it: `DEVICE_23112_MATRIX_LENGTH`
is 25 and `DEVICE_23112_SIZE` is that squared. Taking a square root of 25 gave a
5x5 frame, so the renderer drew a few stray dots in one corner and `GlyphFrame.set`
silently discarded everything outside the grid — 7 lit dots instead of 78.

Also: `clear()` blanks by drawing an empty frame rather than calling
`closeAppMatrix()`, which was closing a channel we no longer open and so left
the last frame lit.

Verified on the device: 78 of 625 dots for a running interval, 234 hardware
writes in 20s, the frame rendering as minutes over seconds inside a draining
ring. 225 tests still pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-19 16:16:30 +03:00
timka123andClaude Opus 5 a7148b69c6 android: the real client — backend, notifications, Live Update, Glyph
The app module was a design gallery: tokens, type and a dial, with no backend,
no notification and nothing driving the rear matrix. This is the rest of it.

**One engine, three views.** `TimerEngine` lives on the Application, not in a
ViewModel, because the Compose screen, the foreground service's notification
and the Glyph must show the *same* second. Two engines polling the same backend
drift apart within seconds and the user sees a notification disagreeing with
the dial. It polls, ticks from a monotonic anchor, and puts every reply through
`:core`'s `reconcile`.

`pomodoro.state()` does not finish an interval whose time is up — it reports
`remaining_seconds = 0` and waits for a client to call `complete`. The tick
loop does, behind the same re-entry guard `desktop/controller.py` uses, since
without one a 1 Hz tick at zero fires `complete` every second until the reply
lands.

**Notifications.** Two channels, because the running interval must be silent
and its *end* must not; one channel cannot be both, and a user who silences a
buzzing countdown has silenced the only part that mattered. The ongoing one is
an Android 16 Live Update: promotion needs `setOngoing` + `setRequestPromotedOngoing`
+ a `ProgressStyle`, and missing any one renders it as an ordinary notification
with no error and no log. Its segments come from `:core`'s `dialTickCount`, so
the status bar, the dial and the Glyph ring agree on what one tick is worth.

**Glyph.** `GlyphMatrixManager.init()` binds `com.nothing.thirdparty/.GlyphService`
and *discards* the boolean `bindService` returns — so on Android 11+ a missing
`<queries>` entry makes the package invisible, the bind silently fail, and the
matrix stay dark with no exception, no log and `onServiceConnected` never
arriving. That was the whole of "the glyph does not work". The manifest now
declares it and `MatrixGlyphDisplay` checks visibility itself rather than
leaving the next person with the same dead end.

The SDK's licence forbids redistribution (clause 2.1(c)), so the .aar stays
git-ignored and `fetch-glyph-sdk.sh` downloads it. Without it a second source
set compiles a no-op display: the app builds, installs and runs with an inert
rear panel, which is also the correct behaviour on any phone that is not a
Nothing.

Verified on the device (Phone (3), Android 16), debug and release: onboarding
against kadence.timka.su, the Live Update with `shortCriticalText` and a 600s
progress track, the matrix accepting 625-dot frames, tasks opening in the Jira
app, and R8 leaving the DTOs decodable. 225 tests, none needing a device.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-19 16:05:13 +03:00
timka123 1e55144291 some backend fixes and add android app 2026-10-19 14:52:20 +03:00