Files
buzz/mobile/lib
Tom Brow f09956179d fix(mobile): keep the composer focused through iOS inactive spells (#9055)
On iPhone, opening Control Center or the app switcher while the composer
is focused can leave the keyboard up over a collapsed composer. The
orphaned keyboard then stays put while you navigate, for example back
from a thread to its channel, and it clips the composer pill.

### Cause

iOS reports a zero keyboard inset while the app is inactive and restores
the keyboard natively when the app returns. The composer treated any
inset drop as a user dismissal: it collapsed, unfocused and removed its
text field. When the keyboard came back, it was attached to no Flutter
field, so nothing could dismiss it. Flutter's own report of the native
side is
[flutter/flutter#189051](https://github.com/flutter/flutter/issues/189051).

### Change

The composer's keyboard observer ignores metrics while the app is not
resumed. iOS reports `resumed` with the inset still at zero and brings
the keyboard back a few hundred milliseconds later, so when a keyboard
that was up hasn't returned at resume, the composer waits a one-second
grace before treating it as dismissed. Any nonzero inset in that window
cancels the wait. A restored keyboard leaves the composer expanded and
focused; a keyboard that really stayed down still collapses the composer
once the grace passes.

### Validation

- Extended the existing "returns to the compact capsule when the
keyboard drops" widget journey with both inactive cases in the order iOS
reports them: resumed at zero with the keyboard returning about 400 ms
later (composer stays focused), and resumed with the keyboard staying
down (composer collapses after the grace). It fails without the fix and
against the first revision of this PR.
- Full mobile check and test suite pass.
- iOS 27 simulator (iPhone 17 Pro, debug build of the first revision):
focused the composer, typed, switched to Settings and back, opened and
closed Control Center, sent a message, and left the channel. The
composer stayed focused through each interruption, sending kept focus,
and leaving dismissed the keyboard. Limitation: the simulator keeps the
keyboard inset through these interruptions, so it reproduces neither the
original bug nor the resume grace; the on-device inset drop is from the
reporter's screen recording and the Flutter issue.

Human app testing is waived under the mobile testing exception; the
simulator pass above is the automated full-app run.

buzz-review-completed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Tom Brow <tomb@squareup.com>
Co-authored-by: Tom Brow <tomb@squareup.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 13:54:12 -08:00
..