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

@@ -19,6 +19,7 @@ import {
getScrollContainer,
matchModels,
} from '@blocksuite/affine-shared/utils';
import { IS_ANDROID } from '@blocksuite/global/env';
import { Point } from '@blocksuite/global/gfx';
import type { PointerEventState } from '@blocksuite/std';
import { BlockComponent, BlockSelection, TextSelection } from '@blocksuite/std';
@@ -413,7 +414,10 @@ export class PageRootBlockComponent extends BlockComponent<RootBlockModel> {
return !(isNote && displayOnEdgeless);
});
this.contentEditable = String(!this.store.readonly$.value);
// Android IMEs can target this outer editable root instead of a block's
// inline editor, leaving composition text in the DOM without committing it
// to the document model. Keep only the block editors editable on Android.
this.contentEditable = String(!this.store.readonly$.value && !IS_ANDROID);
return html`
<div class="affine-page-root-block-container">${children} ${widgets}</div>