Rebuilt from ai-app-2 38bf630, arm64-v8a release, 9,651,616 bytes (lib/arm64-v8a/libmain.so 7,518,840 -- the only .so in the APK, checked rather than assumed, since the ABI trap below is what this build had to dodge). What is new for the phone, both unconfirmed there and both from Iris's 2026-09-07 night report: - A finger put down on a moving list stops the fling at that sample and pans from it with no DRAG_SLOP wait (Compose's `startDragImmediately = isScrollInProgress`); a catch released without moving is not a tap. - A mask carries a shape rather than a rectangle, so a code fence clips on its own rounded corners instead of an inner square, nested clips multiply their coverage, and touch obeys the same shape. Also in it: the winit/Android renderer no longer aborts on a device whose only usable adapter is GLES, and a frame report's `primitives=` no longer counts undrawn clip shapes. The build itself needed ai-app-2's `build-apk.sh` fix landing in the same pass: Gradle's merged-native-libs cache survives `rm -rf jniLibs`, so with an x86_64 lib left in this checkout from emulator work, the "arm64" APK would have carried x86_64 and aborted on the phone with a Vulkan error that has nothing to do with Vulkan. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
503 lines
32 KiB
Markdown
503 lines
32 KiB
Markdown
# ai-app bench
|
|
|
|
The two APKs for the phone benchmark gate (ai-app's `docs/RUST.md`, P0),
|
|
packaged for Dev Updater so they can be installed on a phone without a
|
|
build machine. Add this checkout as a project in Dev Updater (its
|
|
`.dev-updater.ron` names two APK components, `compose-bench` and
|
|
`iris-bench`, with no build step -- the APKs are committed under
|
|
`compose/` and `iris/`), then install each from its card. Both install
|
|
beside the real app under their own application ids and need no server,
|
|
no enrolment and no permissions.
|
|
|
|
The rest of this file is the runbook that was delivered with the APKs.
|
|
|
|
**2026-09-08: catching a moving list, and rounded code fences that clip
|
|
on the curve.** `iris-bench-arm64.apk` rebuilt from ai-app-2 `38bf630`.
|
|
Two things from your last report, and both want checking on the phone
|
|
because neither is confirmed there yet:
|
|
|
|
- **"Sometimes when I try to catch it while it's still moving
|
|
(particularly if I drag) then it fails to stop & snap to where finger
|
|
is."** A finger put down on a moving list now stops the fling *at that
|
|
sample* and drags from it with no slop wait, which is what Compose
|
|
does. A catch you put down and lift without moving is no longer
|
|
treated as a tap. What to try: flick hard, then put a finger down
|
|
mid-flight and drag slowly — the content should be pinned to your
|
|
finger from the first movement, not after a jump.
|
|
- **Code blocks clip on their rounded corners.** A mask carries a shape
|
|
now rather than a rectangle, so a code fence's content is cut on the
|
|
panel's own curve instead of an inner square, and the corners of
|
|
nested clips multiply their alpha rather than fighting. Touch obeys
|
|
the same shape: a corner rounded away is not pressable. What to try:
|
|
scroll a code block sideways and look at its four corners, and try
|
|
pressing just outside one.
|
|
|
|
Also in this build: the app no longer refuses to start on a device whose
|
|
only usable adapter is a GLES one (it falls back and says so in the log
|
|
rather than aborting), and `primitives=` in a frame report no longer
|
|
counts clip shapes that are never drawn.
|
|
|
|
If something is wrong, the **Copy report** button always copies now —
|
|
the log tail comes with it, and Dev Updater's **Runtime** tab on this
|
|
component reads the app's log directly off the phone.
|
|
|
|
|
|
**2026-09-06: composing text + caret, composer layout, text survives app
|
|
switch.** `iris-bench-arm64.apk` rebuilt on top of the fling/stream/type/
|
|
keyboard bench v2 above (same commit range, merged). Fixes from Iris's
|
|
phone report on the previous build: Gboard's composing keystrokes now sync
|
|
back to the app (`InputMethodManager.updateSelection`, previously never
|
|
called, which is why typing looked stuck until a space); swiping over the
|
|
composer bar no longer opens the keyboard (only a completed tap does,
|
|
confirmed on the emulator); and text no longer disappears after leaving
|
|
and returning to the app (a genuinely new renderer now clears the CPU-side
|
|
glyph cache instead of leaving it pointed at a destroyed GPU device). The
|
|
composer itself was also rebuilt as one widget with a height cap and
|
|
insets-aware bottom padding. **Not fixed**: composed/typed text still does
|
|
not become visible on screen at all, a separate, deeper bug found while
|
|
verifying the above -- ruled out as a widget-layout bug (a new unit test
|
|
proves the region math is correct), still open. See ai-app-2's
|
|
`docs/RUST.md`, P0 box, for the full account, what was verified on the
|
|
emulator, and what still needs a real device or Vulkan to isolate.
|
|
|
|
**2026-09-06: bench v2 (fling/stream/type/keyboard).** `compose-bench-arm64.apk`
|
|
rebuilt with the four-phase benchmark Iris asked for after using v1 on her
|
|
phone -- a real fling (12,000px/s through the list's own `FlingBehavior`,
|
|
not the old tween-based swipe, so it travels much further per gesture),
|
|
the existing 400-event/20s stream, a type phase (600 fixed characters
|
|
typed into the real composer then deleted, to exercise wrapping and the
|
|
transcript being pushed upward), and a keyboard phase (five show/hide
|
|
cycles). The report gains a `per phase:` block (frames/late/percentiles/
|
|
worst/duration per phase) ahead of the existing whole-run sections, and
|
|
`bench:` gains the fling phase's travel, the typed character count, and
|
|
how many of the ten keyboard toggles were confirmed by the platform. Full
|
|
spec and the emulator smoke run are in ai-app-2's `docs/RUST.md`, P0 box,
|
|
"Benchmark v2 (2026-09-06)". Same steps below still apply -- "Run
|
|
benchmark" is unchanged in name and location.
|
|
|
|
---
|
|
|
|
# P0 benchmark APKs
|
|
|
|
Two arm64 builds, asked for in docs/RUST.md's P0 box (the phone benchmark gate Iris asked for
|
|
2026-09-05, "before P1 I'd like to see benchmarks & also maybe stress test on my own phone"). Each
|
|
opens straight onto the same synthetic fixture transcript with no server, runs the same scripted
|
|
scroll-and-stream benchmark, and produces a text report to paste back. **Install both, run both,
|
|
paste both reports back** -- the gate is a comparison, not either number alone.
|
|
|
|
## Compose (`compose-bench-arm64.apk`)
|
|
|
|
1. Install it (it has its own application id, `com.example.aiapp.bench`, and its own label "AI
|
|
Sessions bench" -- it installs beside a real enrolled "AI Sessions" without touching it).
|
|
2. Open it. It goes straight to a session screen holding the fixture transcript -- no enrollment,
|
|
no permission prompts.
|
|
3. Tap the gear icon top-right ("Session settings").
|
|
4. Tap "Run benchmark". It scrolls the transcript (the same 24-swipe loop
|
|
`app/transcript-bench.sh` drives on a phone from a computer), then streams 400 more fixture
|
|
events in over 20 seconds pinned to the newest end (the same shape `app/stream-bench.sh`
|
|
measures), then copies a report to the clipboard and shows a toast.
|
|
5. Paste the clipboard back here (or in whatever you're pasting reports into). It is plain text
|
|
with units on every number: frame counts and percentiles, the draw-phase accounting, and a
|
|
`bench:` section this build added -- process CPU time, peak RSS, and battery current sampled
|
|
once a second (says "unavailable" rather than a fabricated number where the phone can't answer,
|
|
per this project's rule against showing an inferred value as a measured one).
|
|
6. If you want to run it again, "Run benchmark" can be pressed more than once -- each press resets
|
|
the counters first, so the report only covers that run's own scroll and stream.
|
|
|
|
Built from `app/androidApp`'s `bench` build type; see `app/build-apk.sh bench` and
|
|
`app/bench-fixture/README.md` for how the fixture it opens was generated (deterministic, checked
|
|
into the repo, never a real transcript).
|
|
|
|
## iris (`iris-bench-arm64.apk`)
|
|
|
|
1. Install it -- own application id, `dev.iris.android.demo.bench` (an `applicationIdSuffix` on
|
|
the same `dev.iris.android.demo` the plain iris tabs demo uses, so it installs beside that one
|
|
too), needs no permissions beyond `INTERNET` (unused here -- inherited from the same manifest
|
|
`transcript-screen` needs, harmless for a build that talks to nothing).
|
|
2. Open it. Same fixture as the Compose build (the identical checked-in
|
|
`app/bench-fixture/assets/transcript.jsonl`), opened with no server through `client-core`'s real
|
|
`fold_page` -- there is no enrollment step here at all, iris's shell has none yet.
|
|
3. Tap "Run benchmark" (the whole screen is just two buttons above the transcript and a report
|
|
area below it -- no settings dialog to find it in). It runs the identical scripted loop: the
|
|
same 24-swipe/6-cycle scroll (900px over 200ms, 500ms apart, animated in ~60Hz steps rather than
|
|
jumped so real frames render along the way), then the same 400-event/20s streaming phase pinned
|
|
to the newest end, through `fold_event` -- the same fold path a live SSE reply uses.
|
|
4. The report appears in the text area under the buttons (it is a selectable field, so it can be
|
|
copied by hand too) and is logged under logcat's `iris-android-app` tag on the line starting
|
|
`iris bench report:`. Tap "Copy report" to put it on the clipboard through the shell's own
|
|
`ClipboardManager` (no toast -- watch logcat or the on-screen text for confirmation it worked).
|
|
5. Paste it back. Same units, most lines the same shape as Compose's -- frame count, janky
|
|
percentage, p50/p90/p99/worst -- plus iris's own CPU/GPU split (`cpu_p50`/`gpu_wait_p50`, from
|
|
`FrameReport::record_split`) where Compose's report has its draw-phase accounting instead, and a
|
|
`bench:`-shaped tail with the same three added fields: process CPU time over the run
|
|
(`getrusage(RUSAGE_SELF)`), peak RSS (`/proc/self/status`'s `VmHWM`), and battery current sampled
|
|
once a second through `BatteryManager.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW)` -- "no
|
|
frames recorded" / "unavailable" rather than a fabricated number wherever the phone can't answer
|
|
one, same rule Compose's report follows.
|
|
6. "Run benchmark" can be pressed again; it resets `FrameReport` first, so a second run's report
|
|
covers only that run.
|
|
|
|
Built with `iris/android-app/build-apk.sh release --abi arm64-v8a` (wraps `cargo ndk -t arm64-v8a
|
|
-P 26 -o app/src/main/jniLibs/ build --release --features "transcript-screen bench"` plus `gradle
|
|
:app:assembleRelease`, signed with the same `~/.config/ai-app/release.jks` `app/build-apk.sh`
|
|
generates, and verifies the result with `aapt2`/`apksigner`). **No longer built with `force-gles`
|
|
as of the 2026-09-06 rebuild below** -- see that entry for why it was there and why it had to come
|
|
out for a phone build specifically.
|
|
|
|
**2026-09-06, commit `46d3a6f`**: rebuilt after `transcript_ui::TranscriptScreen::apply` replaced
|
|
the full-rebuild-per-event streaming path in all three iris clients (docs/RUST.md's P0 box has the
|
|
before/after numbers) -- this is the build to use if comparing against an iris APK from before that
|
|
commit.
|
|
|
|
**2026-09-06, second rebuild, ai-app-2 commit `46246ea`**: this build aborted on Iris's
|
|
phone (a Pixel, GrapheneOS) in `AndroidRenderer::new`, on the very first `surface_changed`, with
|
|
only `wgpu error: Validation Error` surviving into the crash report before Android truncated it.
|
|
Two things changed:
|
|
|
|
1. **A renderer-creation failure no longer aborts the process.** `iris_core::UiRenderNode::new`
|
|
now runs its bind-group-layout/pipeline creation inside wgpu error scopes and returns
|
|
`Result<Self, String>` instead of letting wgpu's default handler panic; the Android backend
|
|
turns a failure into the adapter's identity, the exact limits and downlevel flags bind-group
|
|
layouts validate against, and wgpu's own "Caused by" chain, logged as one line under the
|
|
`iris-android-app` logcat tag and shown on screen as plain, selectable, scrollable text (a
|
|
`TextView` swapped in for the whole activity) saying to copy it and send it back. If this build
|
|
still fails on the phone, **that screen is what to screenshot or copy** -- there is no more
|
|
silent abort to chase through a truncated crash report.
|
|
2. **This build no longer forces the GLES backend.** Every earlier `iris-bench-arm64.apk`
|
|
(including the one above) was built with `--features "... force-gles ..."`, a flag that exists
|
|
only to force the *emulator* off its default software Vulkan and onto GLES for one specific
|
|
frame-time measurement (RUST.md's I5) -- its own doc in `iris/Cargo.toml` never mentions real
|
|
hardware. `build-apk.sh`'s default feature list carried it into every arm64 build regardless,
|
|
so the APK actually delivered to a phone was locked to GLES rather than the phone's own Vulkan
|
|
driver. That is the named hypothesis for the crash (docs/RUST.md's P0 box has the full audit):
|
|
GLES support for a storage buffer bound in the *vertex* stage (`move_offsets`, `masks_layout`)
|
|
depends on the driver reporting `GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS > 0`, which real Vulkan
|
|
grants unconditionally but a phone's GLES path is not guaranteed to -- and RUST.md's own
|
|
SwiftShader finding already flagged GLES-on-Android as the fragile backend for this exact
|
|
shader. This build uses the default backend (Vulkan on a real device) instead.
|
|
|
|
If this rebuild still crashes, the on-screen report from point 1 names the real cause directly;
|
|
paste it back rather than guessing further from a truncated log.
|
|
|
|
## 2026-09-06, later: bundled fonts, content-scale fix, Diagnostics control
|
|
|
|
Iris's first real-phone report on the previous rebuild (no crash) found four
|
|
defects the emulator never showed: every glyph disappearing on the first tap
|
|
or scroll (rectangles stay drawn -- not root-caused this pass, but a phone
|
|
report from this build's new Diagnostics page would help), bold words
|
|
rendering as blank gaps (fixed -- bundled Noto Sans/Noto Sans Mono, static
|
|
per-style faces, ahead of the platform's own fonts), text far too small
|
|
(fixed -- iris had no device-pixel-ratio handling on either platform before
|
|
this; density now divides window size, touch coordinates and the shader's
|
|
window uniform down to logical units), and the top buttons sitting under the
|
|
status bar (fixed -- a new `AndroidAppState::on_insets_changed` hook, unused
|
|
until now).
|
|
|
|
This build also adds a third **Diagnostics** button next to Run/Copy,
|
|
filling the report area with adapter identity, font resolution, the atlas's
|
|
view count, every wgpu error seen since surface creation, and the frame
|
|
report -- "copy this and send it to Iris" via the existing Copy button.
|
|
|
|
Full account, including what's still unverified on a real phone, in
|
|
`docs/RUST.md`'s P0 box in the `ai-app-2` repo (`rustify` branch).
|
|
|
|
## 2026-09-06, later still: keyboard-wipe fix, a density unit for crisp text, header background
|
|
|
|
Iris's report on the previous rebuild, with screenshots: text now the
|
|
right size but **blurry**; opening the keyboard still **wipes every
|
|
glyph** (rectangles stay, only text disappears); the **header buttons
|
|
have nothing behind them and overlap the transcript text**.
|
|
|
|
- **Keyboard wipe**: `surface_changed` fires on every surface resize, not
|
|
only a genuinely new surface -- showing the keyboard under
|
|
`adjustResize` is exactly such a resize. It was rebuilding the whole
|
|
renderer (a fresh, empty glyph atlas) every time, while the CPU-side
|
|
glyph cache kept coordinates into the *old* atlas. Fixed: reuse the
|
|
existing renderer's device/atlas/buffers and only reconfigure the
|
|
surface when one is already live. Confirmed on this checkout's own
|
|
emulator two ways (a forced display resize and an actual soft-keyboard
|
|
open) -- text stayed on screen both times.
|
|
- **Blur**: the previous fix's global "logical size" stretch (window
|
|
divided by density, then displayed stretched back up) rasterised each
|
|
glyph small and displayed it bigger than it had texels for. Fixed with
|
|
the density-independent length unit Iris asked for the same day (a new
|
|
`dp` alongside the existing physical-pixel and relative lengths,
|
|
resolved against the display's density at layout time) -- text now
|
|
rasterises at the display's real physical resolution.
|
|
- **Header**: only each button's own coloured rect painted anything, so
|
|
gaps between/around them showed the black clear colour one layer back,
|
|
and the row's reserved height did not match the (now density-correct)
|
|
transcript below it. Fixed with an opaque panel behind the whole row
|
|
and every header size moved onto the new `dp` unit.
|
|
- **New**: the bench build now auto-captures a diagnostics report ~500ms
|
|
after the keyboard opens (logged, copied to the clipboard, and shown in
|
|
a plain overlay with Copy/Close over the running app) -- so a report
|
|
can come back even if a keyboard-triggered regression is still
|
|
happening.
|
|
|
|
**Not fully verified.** This build has not been run on Iris's actual
|
|
phone. It was verified end to end on this checkout's own emulator
|
|
(`run-bench.sh`, no crash, 24/24 swipes, 400/400 streamed events;
|
|
before/after screenshots for the two keyboard-resize tests above). While
|
|
verifying, a **separate, not-yet-fixed issue turned up**: after a
|
|
keyboard-triggered resize, the header row appeared to render a second
|
|
time, out of place, inside the transcript area, and a tap meant for the
|
|
message field below landed on a header button instead (a benchmark run
|
|
started unexpectedly). Not root-caused, and not confirmed to be caused by
|
|
this pass's changes rather than something pre-existing -- worth watching
|
|
for on the phone and reporting back if seen. Full account in
|
|
`docs/RUST.md`'s P0 box in the `ai-app-2` repo (`rustify` branch).
|
|
|
|
## 2026-09-06, later still: Benchmark v2 (fling/type/keyboard), the header-duplicate finding, the ime-inset finding
|
|
|
|
**New**: "Run benchmark" now runs the same four-phase script the Compose
|
|
build's v2 does -- fling (8 flings out + 8 back at 12,000px/s through
|
|
`List`'s own new fling, matching Android's real deceleration curve),
|
|
stream (unchanged), type (the same 600-character string, one character
|
|
per 50ms into the real composer, then deleted), and keyboard (five
|
|
show/hide cycles). The report gained a `per phase:` block (frames, late
|
|
%, p50/p90/p99, worst per phase) and the whole-run `frames:` line now
|
|
reads the display's real refresh rate instead of assuming 60Hz.
|
|
|
|
**The header-duplicate bug from the previous entry: still not fixed.**
|
|
Reproduced reliably this pass (tap the composer field, screenshot after
|
|
the keyboard opens -- the three-button row appears twice, once at its
|
|
real position and once inside the transcript). One real, targeted fix
|
|
was tried and **ruled out**: skipping the header rebuild when the
|
|
status-bar inset hasn't actually changed (since a keyboard toggle also
|
|
re-fires this callback for an unrelated reason) -- the duplicate still
|
|
reproduced identically after that fix, so repeated rebuilding is not the
|
|
cause. Still unexplained; needs either live instrumentation of the
|
|
layout engine's two-phase span placement or a person with the phone.
|
|
|
|
**Found, and partly explains why the keyboard phase and the
|
|
keyboard-open auto-diagnostics both read "not confirmed" on every
|
|
run so far**: this app's `AndroidManifest.xml` uses
|
|
`windowSoftInputMode="adjustResize"` (needed so the keyboard resizes the
|
|
window instead of panning it off screen), and under `adjustResize`
|
|
`WindowInsets.Type.ime()`'s own inset *amount* is defined to read zero --
|
|
the window already shrank to avoid the overlap that inset would
|
|
otherwise report. Fixed the app to read `WindowInsets.isVisible(ime())`
|
|
(a boolean, unaffected by resize-vs-pan) instead of the numeric inset --
|
|
correct on its own terms, but on this emulator the insets listener still
|
|
never re-fires at all once the keyboard opens (a separate, deeper
|
|
platform behavior tied to this activity not being edge-to-edge, not
|
|
fixed this pass -- changing that is a bigger, riskier window-behavior
|
|
change than the time available justified). So the keyboard phase's "0
|
|
confirmed" and the auto-diagnostics not firing are both still open,
|
|
now for a specific, named reason rather than an unknown one.
|
|
|
|
Full account, including what was tried and ruled out, in
|
|
`docs/RUST.md`'s P0 box in the `ai-app-2` repo (`rustify` branch).
|
|
|
|
## 2026-09-06, evening: typing, launch layout, fling, per-block streaming, doubled rows
|
|
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 commit `20303e0` (arm64 Vulkan release,
|
|
`iris/android-app/build-apk.sh release --abi arm64-v8a --features "transcript-screen bench"`).
|
|
Everything since the 02:07 build, in one entry -- two intermediate builds went to the wrong
|
|
folder and never reached this repo:
|
|
|
|
- **Launch layout**: the black third below the composer was the bench shell's own empty
|
|
report pane taking a third of the screen, not an inset bug. Sized to its content now.
|
|
- **Typing**: tapping the empty composer focused it with no caret, so every keystroke was
|
|
dropped. Fixed, with a regression test. Text should appear as you type.
|
|
- **Fling and swipe from the composer**: dragging is now iris's own `DragGesture` with pointer
|
|
capture. A fast swipe keeps moving after release; a pan starting on the grey bar is taken by
|
|
the list from the frame it commits.
|
|
- **Doubled rows** (the `Compacted:` row, and the earlier doubled header): a widget redrawn
|
|
through its ancestor while marked dirty never freed its previous primitives, so they were
|
|
drawn every frame for the life of the process. Fixed; a debug-build assertion now checks
|
|
every frame that no primitive outlives its widget.
|
|
- **Streaming re-lays out only the block the delta lands in.** A message row is a column of
|
|
one text widget per markdown block; a streamed delta replaces the last block only (one text
|
|
shape per delta into a 100-paragraph reply, by counter). Emulator stream-phase p99 went
|
|
343ms -> 137ms. **The stream phase on your phone is the number to look at** (it was p50
|
|
18.2ms vs Compose's 13.4ms before).
|
|
- **Selection is per block**: a drag selects within and across blocks; copy joins them. Whether
|
|
a block should be the selection unit is yours to judge (`docs/DECISIONS.md`, 2026-09-06).
|
|
- **The composer scrolls under a finger** when it overflows its six-line cap.
|
|
- Also fixed: every widget's tap target sat short of its drawing by its last move (from
|
|
launch); stale mask slots after a keyboard resize; a targeted-redraw abort on masked
|
|
widgets; the full-screen diagnostics overlay on every keyboard open is gone (logged only).
|
|
- **App-switch text loss** did not reproduce on the emulator, so this build logs one line per
|
|
surface event with glyph counts. If text still vanishes on returning to the app, please send
|
|
`adb logcat | grep -i iris` from around the return; `already_live=true` on the way back in
|
|
names the cause outright.
|
|
|
|
Not in this build: markdown block styling (headings, highlighted fences, lists, tables, links)
|
|
and tool-call cards, which landed on `rustify` after it -- next build.
|
|
|
|
## 2026-09-07: the keyboard reopens, the composer moves for the IME, and a fling actually flings
|
|
|
|
From `ai-app-2` commit `ba0f2ea` on `rustify` (`iris-bench-arm64.apk`, arm64 release,
|
|
minSdk is 29 now). This build answers all four items of your 22:16 report.
|
|
|
|
- **"I can't reopen keyboard by tapping on message box."** Fixed. Dismissing the keyboard
|
|
leaves the field focused, and the only code path that asked for the keyboard was the one
|
|
that ran when a field *became* focused, so it never ran again. A tap on an already-focused
|
|
field asks for it now, exactly as Android's own `EditText` does. Checked on the emulator
|
|
both ways: with the fix the second tap opens it, without it the second tap does nothing.
|
|
Swiping over the composer still summons nothing, which is the thing this could have broken.
|
|
- **"Message box does not push up the scroll area."** Fixed. The keyboard's *height* was being
|
|
sent across to Rust as the boolean 1, so nothing had a number to pad by. Height and
|
|
visibility are two separate values now. On the emulator the composer rises by exactly the
|
|
keyboard's height and the transcript shrinks to match.
|
|
- **"Fling still doesn't work."** Three separate faults, all fixed, and **this is the one to
|
|
test hardest** because the emulator cannot reproduce your phone's input timing.
|
|
1. A fast flick at 120Hz arrives as one or two events with the in-between positions batched
|
|
inside them, and we were reading only the last position -- so the speed came out as zero.
|
|
Every batched sample is replayed now, each with its own timestamp.
|
|
2. Nothing in iris advanced a fling between input events at all. The benchmark drove its own
|
|
fling loop, which is why the bench "flung" and a finger never did. Widgets can animate now.
|
|
3. Once flings finally moved, one lasted 45 seconds: two constants were wrong (a hardcoded
|
|
display density, and the scroll friction used where Android uses its own 0.84 tuning
|
|
number -- a factor of 56 inside an exponential). A flick now coasts for the time Android's
|
|
own formula says: 1.6s for a hard flick, 0.6s for a gentle one.
|
|
|
|
**If it still does not fling on your phone**, the one line that settles it is
|
|
`adb logcat | grep "iris drag release"` -- please send it. `samples=1` or `span=0.0ms` means
|
|
the batched samples are not reaching us on your device; a sensible span with `v=` in the
|
|
thousands and `outcome=Released(Some(...))` means the gesture is measured correctly and
|
|
whatever is wrong is after that point. `outcome=Tapped` means the flick never counted as a
|
|
drag at all.
|
|
- **"The textures are getting cooked after leaving the app and resuming."** Fixed in
|
|
`ba2afba`, with a headless test, but **not confirmed on a device**: no emulator here has a
|
|
Vulkan adapter and the GLES path may not destroy the surface at all, so this one needs your
|
|
phone. The cause was one cache deeper than the last build's fix reached -- each text widget
|
|
kept its own laid-out glyphs with the *old* atlas's coordinates and re-submitted them
|
|
verbatim, which is why only text drawn after the resume looked right. The atlas carries a
|
|
generation now and a cleared atlas invalidates every cached layout at once.
|
|
|
|
Also in this build, both found while checking the above: a tap on the composer aborted every
|
|
debug build (a fixed bound on how deep a widget can nest was 16 and the composer is 17 deep --
|
|
in a release build like this one it did not crash, it silently drew and hit-tested that part of
|
|
the tree in the wrong place), and the app now requires Android 10 or newer, because the
|
|
per-sample touch timestamps the fling fix needs are API 29.
|
|
|
|
Still not fixed, and unrelated to any of the above: the composer bar's grey background is not
|
|
drawn on this build, so the transcript shows through behind the message field.
|
|
|
|
## 2026-09-07, later: the fling curve was a straight line, and the keyboard was one build setting
|
|
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `rustify` commit `4274b8b`.
|
|
This is the build for your three lines on the last one.
|
|
|
|
**"It seems to just be linear velocity with an abrupt stop."** It was
|
|
exactly that, and not approximately -- the curve iris used to shape a
|
|
fling returned a straight line for every input. Android's own deceleration
|
|
curve is built by a loop that solves one cubic and samples a *different*
|
|
one; iris had both halves solving and sampling the same one, which made the
|
|
two tables it builds identical, and the lookup that reads one against the
|
|
other then cancels out to "distance is proportional to time". So a flick
|
|
coasted at its release speed for the whole (correctly computed) duration
|
|
and then stopped dead at the end of it.
|
|
|
|
It is ported exactly now, from Android's `OverScroller.java` and from
|
|
Compose's own copy of the same curve, which agree line for line -- so a
|
|
fling here should travel and slow the way every other Android scroll view
|
|
does. On the emulator a released 3750px/s now decelerates
|
|
3746 -> 2624 -> 1834 -> 1144 -> 752 -> 449 -> 243 -> 83px/s across 32
|
|
frames, where before it would have held 3750 for all of them. **What to
|
|
look for**: a flick should visibly slow before it stops, and a longer flick
|
|
should slow over a longer distance. Two things that also should hold, both
|
|
checked here: a flick into the top or bottom of the transcript stops there
|
|
without bouncing, and putting a finger down during a fling stops it dead.
|
|
|
|
Worth saying because it is the reason this took two builds: every test the
|
|
fling code had compared it against itself -- is it monotonic, is the sign
|
|
right, does it add up to the total -- and **all of them pass on a straight
|
|
line**. The expected numbers are now generated by a separate transcription
|
|
of Android's source that does not share a line of code with iris.
|
|
|
|
**"The keyboard raising up does not push things upwards."** This one was a
|
|
single line of the bench app's build file: it declared it targeted Android
|
|
14, while the real app (the Compose one, whose keyboard does push its
|
|
transcript up on your phone) declares 17. Below the Android 15 target line
|
|
a window keeps the old behaviour, where the system shrinks the window for
|
|
the keyboard and therefore reports the keyboard's height to the app as
|
|
zero -- nothing left to push up. The emulator here is a version where the
|
|
old opt-out still works, which is why it pushed up in every test run and
|
|
not on your phone.
|
|
|
|
**This one is a reading, not a measurement** -- there is no Android 17
|
|
device I can reach. So the other half of the change is making your phone
|
|
able to answer it without a log. **Press `Diagnostics` with the keyboard
|
|
open and screenshot the line beginning `insets:`.** It looks like
|
|
|
|
insets: dispatches=27 left=0 top=142 right=0 bottom=63 ime_bottom=0 ime_visible=false
|
|
|
|
- `ime_bottom` in the hundreds, and the message box has risen: fixed.
|
|
- `dispatches` counting up but `ime_bottom=0`: my reading was wrong and the
|
|
window is still being resized. That is the useful failure.
|
|
- `dispatches=0`: the system is not telling the app about insets at all,
|
|
which is a third thing again and would say so in words instead of
|
|
numbers.
|
|
|
|
The keyboard's height also arrives over a second path now (the animation
|
|
callback), so the push-up follows the keyboard up rather than jumping when
|
|
it lands.
|
|
|
|
**"The resume glyph corruption is fixed."** Thank you -- closed on your
|
|
evidence. That was the one nothing here could ever have confirmed: no
|
|
emulator on this machine has a Vulkan adapter, and the software path may
|
|
not destroy the surface at all, so the state you photographed was not
|
|
reproducible here.
|
|
|
|
Still not fixed, and still unrelated: the composer bar's grey background is
|
|
not drawn on this build, so the transcript shows through behind the message
|
|
field.
|
|
|
|
## 2026-09-07, evening: clamped scrolling, a faster flick start, platform fonts, enrollment, and a runtime log Dev Updater can read
|
|
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `rustify` commit `92985ba`,
|
|
against the last delivery (`b47eb73`, the fling-curve + keyboard-targetSdk
|
|
build). APK **9,639,224 bytes**, `libmain.so` **7,506,448 bytes** (arm64-v8a
|
|
only) -- both smaller than that build, mostly from replacing the bundled
|
|
Noto fonts with the platform's own (Roboto for body text, Droid Sans Mono
|
|
for code) and a further release-profile tuning pass; docs/RUST.md has the
|
|
full size table.
|
|
|
|
What changed:
|
|
|
|
- The list is now clipped to its own box and rows are drawn at both edges --
|
|
nothing scrolls up behind the header, and there is no blank band at
|
|
either end.
|
|
- Scrolling is clamped at both ends of the transcript, matching the fling
|
|
fix from the last build: you cannot drag or fling past the top or the
|
|
bottom.
|
|
- A released flick now starts at the speed your finger was actually moving
|
|
at, using the same least-squares velocity estimator Compose itself uses,
|
|
rather than a slower approximation -- a flick should feel like it starts
|
|
fast and decelerates, not like it ramps up.
|
|
- The clock that timestamps each touch sample was misdating batched input,
|
|
which fed wrong numbers into that velocity estimate; it now dates them
|
|
correctly.
|
|
- Code blocks render in a real monospace font and body text in Roboto --
|
|
both platform fonts now, not the bundled Noto this build removes.
|
|
- The app enrols itself from the `aiapp://enroll` link -- Dev Updater's
|
|
Enroll button on this APK's component opens it directly. Diagnostics
|
|
shows either `enrolled: host:port` or `not enrolled`.
|
|
- The app exposes its own log to Dev Updater: APK component -> log button
|
|
-> Runtime tab. This needs the updated Dev Updater build on the host to
|
|
show anything.
|
|
- A "Trace" switch in the bench header turns on a line per input and per
|
|
frame in that log, for when a report alone isn't enough to say what
|
|
happened.
|
|
- Several of the invariants this code relies on internally are now hard
|
|
assertions in this release build, rather than silently-wrong behaviour if
|
|
one is ever violated.
|
|
|
|
What to look for:
|
|
|
|
- The header shows nothing behind it, at either edge of a scroll.
|
|
- You cannot scroll past the top or the bottom of the transcript.
|
|
- A flick starts at roughly the speed of your finger and visibly
|
|
decelerates, rather than ramping up or holding a constant speed.
|
|
- Code blocks are monospace; body text is not.
|
|
- Opening the keyboard pushes the composer up. If it doesn't, screenshot
|
|
Diagnostics' `insets:` line as in the last build's report.
|
|
- Dev Updater's Runtime tab (APK component -> log button) shows this app's
|
|
own lines, once the host's Dev Updater is updated.
|
|
- With Trace on, do a few flicks, then press Copy in the render report --
|
|
the input log that comes back is what to send back here.
|