fix(android): stabilize IME composition and deletion handling (#15370)

## Summary
Fix Android editor IME corruption around composition, autocorrect
replay, delete, Enter, and old WebView delete behavior.

## What changed
- Add Android WebView InputConnection wrapper for editor IME handling.
- Route Android delete events through BlockSuite editor input.
- Guard against keyboard autocorrect/composition replay after delete or
space.
- Stabilize delete fallback on older Android/WebView versions.
- Gate IME diagnostic logs behind debug builds.
- Add Android IME fix notes and regression coverage.

## Validation
- Manual Android testing passed.
- `git diff --check upstream/canary...HEAD`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved Android text editing for Backspace, Delete, Enter, composing
text, and keyboard events.
  * Prevented input methods from targeting the wrong editor area.
* Improved caret-based text handling, focus synchronization, and
composing-session cleanup.

* **Platform Improvements**
* Added a dedicated Android input bridge for smoother IME interactions
and fallback keyboard behavior.
* Improved editor actions, input recovery, and trusted-page validation
for Android communication.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: DarkSky <darksky2048@gmail.com>
This commit is contained in:
qiaoyanfei
2026-08-21 13:55:14 +08:00
committed by GitHub
parent 3feb17cde3
commit 591f874dad
14 changed files with 1142 additions and 17 deletions

View File

@@ -57,12 +57,14 @@ export function getPrefixText(inlineEditor: InlineEditor) {
const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange || inlineRange.length > 0) return '';
const nearestLineBreakIndex = inlineEditor.yTextString
.slice(0, inlineRange.index)
.lastIndexOf('\n');
const prefixText = inlineEditor.yTextString.slice(
nearestLineBreakIndex + 1,
inlineRange.index
);
return prefixText;
const maxMarkdownPrefixLength = 512;
const prefixStart = Math.max(0, inlineRange.index - maxMarkdownPrefixLength);
const yTextString = inlineEditor.yTextString;
const prefixWindow = yTextString.slice(prefixStart, inlineRange.index);
const nearestLineBreakIndex = prefixWindow.lastIndexOf('\n');
if (nearestLineBreakIndex === -1 && prefixStart > 0) return '';
return nearestLineBreakIndex === -1
? prefixWindow
: prefixWindow.slice(nearestLineBreakIndex + 1);
}