SIGN IN SIGN UP

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