Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 873449c

Browse files
authored
[Android] Reset IME state in TextInputPlugin.clearTextInputClient (#49829)
## Description This PR calls Android API `InputMethodManager.restartInput` to reset IMEs internal states. Otherwise some IMEs (Gboard for instance) keep reacting based on the previous input configuration until a new configuration is set. - On Android native, `restartInput` is called in several places, for instance in https://github.com/AndroidSDKSources/android-sdk-sources-for-api-level-34/blob/f2197987748faef78e869662ae1fd039daa22a63/android/widget/TextView.java#L2458. - On Compose, flutter/flutter#70546 (comment) pointed out where it is called. - On Flutter, it is called at some point but mainly when another `TextField` is focused (it is mainly called in `setTextInputEditingState`). ## Related Issue Fixes flutter/flutter#70546. ## Tests Adds 1 test.
1 parent bfdc0c5 commit 873449c

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,10 @@ void clearTextInputClient() {
569569
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
570570
unlockPlatformViewInputConnection();
571571
lastClientRect = null;
572+
573+
// Call restartInput to reset IME internal states. Otherwise some IMEs (Gboard for instance)
574+
// keep reacting based on the previous input configuration until a new configuration is set.
575+
mImm.restartInput(mView);
572576
}
573577

574578
private static class InputTarget {

shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,41 @@ public void setTextInputEditingState_nullInputMethodSubtype() {
11281128
assertEquals(1, testImm.getRestartCount(testView));
11291129
}
11301130

1131+
@Test
1132+
public void clearTextInputClient_alwaysRestartsImm() {
1133+
// Initialize a general TextInputPlugin.
1134+
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
1135+
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
1136+
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
1137+
View testView = new View(ctx);
1138+
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
1139+
TextInputPlugin textInputPlugin =
1140+
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1141+
textInputPlugin.setTextInputClient(
1142+
0,
1143+
new TextInputChannel.Configuration(
1144+
false,
1145+
false,
1146+
true,
1147+
true,
1148+
false,
1149+
TextInputChannel.TextCapitalization.NONE,
1150+
null,
1151+
null,
1152+
null,
1153+
null,
1154+
null,
1155+
null));
1156+
// There's a pending restart since we initialized the text input client. Flush that now.
1157+
textInputPlugin.setTextInputEditingState(
1158+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
1159+
assertEquals(1, testImm.getRestartCount(testView));
1160+
1161+
// A restart is always forced when calling clearTextInputClient().
1162+
textInputPlugin.clearTextInputClient();
1163+
assertEquals(2, testImm.getRestartCount(testView));
1164+
}
1165+
11311166
@Test
11321167
public void destroy_clearTextInputMethodHandler() {
11331168
View testView = new View(ctx);

0 commit comments

Comments
 (0)