fix: reset `isInteractive` when interactive gesture ends without `animateToFinish` (#1526)
## 📜 Description Clear `InteractiveKeyboardProvider.isInteractive` in `KeyboardAnimationController.reset()`. Today the flag is set in `startControlRequest()` / `insetBy()`, but cleared only in `animateToFinish()`. Gestures that end via `cancel()`, or via the control listener's `onFinished` / `onCancelled` paths, all funnel through `reset()` — and none of them clear the flag, so it strands `true` for the rest of the process lifetime. `reset()` is the single choke point every gesture-end path reaches, so clearing it there covers all of them (and is idempotent with the explicit clear in `animateToFinish()`). ## 💡 Motivation and Context Fixes #1525. A stranded `isInteractive` makes `KeyboardAnimationCallback` treat the keyboard as perpetually moving (`isMoving = isTransitioning || InteractiveKeyboardProvider.isInteractive`), which permanently disables the "detected desynchronized state" recovery in `onApplyWindowInsets`. After that, any keyboard hide whose events are lost while the app is backgrounded leaves `KeyboardController.isVisible()` stuck `true` and the Reanimated `height` at the open value — a `KeyboardStickyView` child then renders one keyboard-height above the bottom (keyboard closed) until the app is killed. Likely also the root cause behind the "not reproducible" #1315. The easiest real-world strand: user drags the keyboard down (interactive dismiss) and backgrounds the app mid-gesture (gesture-nav home swipe) — the control request is cancelled, `animateToFinish()` never runs. ## 📢 Changelog ### Android - reset `InteractiveKeyboardProvider.isInteractive` in `KeyboardAnimationController.reset()` so cancelled/aborted interactive gestures don't permanently disable the desynchronized-state recovery ## 🤔 How Has This Been Tested? Deterministic repro from #1525 on an Android 16 emulator (app using the docs' chat pattern — `KeyboardGestureArea` + `KeyboardStickyView`, RN 0.85.3, Fabric): 1. Open keyboard → start an interactive dismiss drag (`adb shell input motionevent DOWN/MOVE...`) → press HOME mid-drag (no UP). 2. Before the fix: every subsequent animation logs `DiffY: … true …` (stranded flag) and `detected desynchronized state` recovery lines never appear again; after backgrounding with the keyboard open, `KeyboardStickyView` content strands one keyboard-height above the bottom and never recovers (only app kill). 3. With the fix: the flag clears when the cancelled gesture funnels through `reset()`, the desync recovery fires on the next `onApplyWindowInsets`, and the stranded position self-corrects on foreground. ## 📝 Checklist - [x] CI successfully passed Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
I
Ido Yana committed
fe777b4ed2ba82ed54660623ed06a446b776e8ce
Parent: 73d3b8a
Committed by GitHub <noreply@github.com>
on 7/3/2026, 9:24:08 AM