iris/android: composing text sync, tap-vs-swipe focus, composer rebuild, atlas reset on app-switch

Four fixes from Iris's phone report on the dc01f88 build, plus her same-day
follow-up on swipe-vs-tap:

- android/ime.rs: InputConnection now calls InputMethodManager.updateSelection
  after every edit (new update_ime_selection, called from after_input) -- Gboard
  was holding keystrokes back with nothing telling it the app's selection/
  composing region had moved, which read as "doesn't enter it until I hit
  space, doesn't move the caret". New unit tests in widget/text/edit.rs cover
  the buffer-level composing/commit/delete/selection operations directly.

- attr.rs: Selector/Selectable rewritten around a shared on_press dispatcher
  over PressStart/Pressing/PressEnd instead of click_or_drag(), so a field
  that isn't already focused only grants focus (and requests the IME) on a
  completed tap -- press and release with no frame past DRAG_SLOP. A drag
  is never consumed, so whatever is behind the field still sees it. New
  FocusHost::is_focused (both platform impls) and TextEdit::press_origin
  back this. Verified on the emulator: dumpsys input_method's mInputShown
  stays false after a swipe over the composer, true after a tap.

- iris_core: GlyphAtlas::clear()/Textures::reset(), called together from
  android/view.rs's surface_changed exactly when a genuinely new renderer is
  built (app-switch, not the keyboard-resize path that already reuses the
  renderer) -- both CPU-side caches otherwise kept pointing at the old,
  destroyed device's textures. Verified on the emulator: home, reopen, every
  glyph still on screen.

- transcript-ui/composer.rs: rebuilt as one widget (unchanged Stack{rect,
  span} idiom, capped at ~6 lines via MaxSize + .scrollable(), wrapped in one
  Pad whose bottom Composer::set_bottom_inset rewrites in place so the bar
  sits on the IME or nav-bar inset with no rebuild -- rebuilding would drop
  focus/selection/in-progress text). Wired from bench_client.rs's existing
  on_insets_changed.

A second, deeper bug found while verifying the composing fix is NOT fixed
this pass: composed text never becomes visible at all. A new layout_tests.rs
test proves the widget tree's own region math is correct across a keyboard
resize, ruling that out; RUST.md's P0 box has the full writeup and what to
check next (UiRenderState::redraw's single-widget path, or something
force-gles-specific -- this AVD has no Vulkan adapter to rule that out with).

cargo fmt/clippy/test --workspace and cargo ndk clippy all clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-06 02:03:00 -04:00
1 parent dc01f88d75
commit 20b12255e1
14 files changed
+628 -15

No files matched your search

+29
View File
@@ -626,3 +626,32 @@ box has the full investigation and the phone verification still to do.
built and checked on this checkout's emulator only. RUST.md's P0 box
says what she should check for: crisp text at two densities, the
keyboard no longer wiping, and the header's background.
## 2026-09-06: composing text, focus-on-tap, and atlas invalidation on a new renderer
Three small but public API changes, from the same phone-report pass as the
entry above (RUST.md's P0 box has the full account, including a real bug
still not root-caused).
- **`FocusHost` gained `is_focused(&self, id) -> bool`** (both platform
impls). `attr.rs`'s `Selector`/`Selectable` used to grant focus (and so
request the IME) on the very first frame of *any* press, before it was
known whether the gesture was a tap or a drag — a swipe over a text
field wrongly summoned the keyboard. They now wait for a completed tap
(press and release with no frame crossing `sense::DRAG_SLOP`) unless the
field is already focused, in which case dragging inside it to select
text is unchanged. `TextEdit` gained one new `pub(crate)` field
(`press_origin`) to track this; no public surface change there.
- **`android::ime`'s `InputConnection` now calls `InputMethodManager::
updateSelection` after every edit** (`IrisViewPeer::update_ime_selection`,
called from `after_input`). Gboard was holding keystrokes back because
nothing ever told it where the app's own selection/composing region had
moved to — this is what android-view's own demo does in its `render()`
and this bridge never did.
- **`GlyphAtlas::clear()` and `Textures::reset()`** (`iris_core`). Called
together, once, from `android::view`'s `surface_changed` exactly when a
*genuinely new* `AndroidRenderer` is built (backgrounding and returning,
not a keyboard-triggered resize, which already reuses the renderer) —
both CPU-side caches otherwise kept pointing at the old, now-destroyed
device's textures, which is why text used to vanish again after leaving
and returning to the app.