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

Commit 766f7be

Browse files
authored
[Android] Call restartInput selectively on clear (#53662)
## Description This PR restricts the call to `restartInput` which was added in #49829. The restart is called when input action is null, DONE, or NONE. ## Related Issue Fixes flutter/flutter#148673. ## Tests Updates 1 test, adds 3 tests.
1 parent 4c42b66 commit 766f7be

2 files changed

Lines changed: 120 additions & 4 deletions

File tree

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,15 +546,22 @@ void clearTextInputClient() {
546546
}
547547
mEditable.removeEditingStateListener(this);
548548
notifyViewExited();
549+
550+
boolean needsRestart =
551+
configuration.inputAction == null
552+
|| configuration.inputAction == EditorInfo.IME_ACTION_DONE
553+
|| configuration.inputAction == EditorInfo.IME_ACTION_NONE;
549554
configuration = null;
550555
updateAutofillConfigurationIfNeeded(null);
551556
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
552557
unlockPlatformViewInputConnection();
553558
lastClientRect = null;
554559

555-
// Call restartInput to reset IME internal states. Otherwise some IMEs (Gboard for instance)
556-
// keep reacting based on the previous input configuration until a new configuration is set.
557-
mImm.restartInput(mView);
560+
if (needsRestart) {
561+
// Call restartInput to reset IME internal states. Otherwise some IMEs (Gboard for instance)
562+
// keep reacting based on the previous input configuration until a new configuration is set.
563+
mImm.restartInput(mView);
564+
}
558565
}
559566

560567
private static class InputTarget {

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

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ public void setTextInputEditingState_nullInputMethodSubtype() {
11311131
}
11321132

11331133
@Test
1134-
public void clearTextInputClient_alwaysRestartsImm() {
1134+
public void clearTextInputClient_restartsImmWhenInputActionIsNull() {
11351135
// Initialize a general TextInputPlugin.
11361136
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
11371137
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
@@ -1165,6 +1165,115 @@ public void clearTextInputClient_alwaysRestartsImm() {
11651165
assertEquals(2, testImm.getRestartCount(testView));
11661166
}
11671167

1168+
@Test
1169+
public void clearTextInputClient_restartsImmWhenInputActionIsDone() {
1170+
// Initialize a general TextInputPlugin.
1171+
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
1172+
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
1173+
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
1174+
View testView = new View(ctx);
1175+
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
1176+
TextInputPlugin textInputPlugin =
1177+
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1178+
textInputPlugin.setTextInputClient(
1179+
0,
1180+
new TextInputChannel.Configuration(
1181+
false,
1182+
false,
1183+
true,
1184+
true,
1185+
false,
1186+
TextInputChannel.TextCapitalization.NONE,
1187+
null,
1188+
EditorInfo.IME_ACTION_DONE,
1189+
null,
1190+
null,
1191+
null,
1192+
null));
1193+
// There's a pending restart since we initialized the text input client. Flush that now.
1194+
textInputPlugin.setTextInputEditingState(
1195+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
1196+
assertEquals(1, testImm.getRestartCount(testView));
1197+
1198+
// A restart should be forced when calling clearTextInputClient() and input action is
1199+
// EditorInfo.IME_ACTION_DONE.
1200+
textInputPlugin.clearTextInputClient();
1201+
assertEquals(2, testImm.getRestartCount(testView));
1202+
}
1203+
1204+
@Test
1205+
public void clearTextInputClient_restartsImmWhenInputActionIsNone() {
1206+
// Initialize a general TextInputPlugin.
1207+
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
1208+
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
1209+
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
1210+
View testView = new View(ctx);
1211+
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
1212+
TextInputPlugin textInputPlugin =
1213+
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1214+
textInputPlugin.setTextInputClient(
1215+
0,
1216+
new TextInputChannel.Configuration(
1217+
false,
1218+
false,
1219+
true,
1220+
true,
1221+
false,
1222+
TextInputChannel.TextCapitalization.NONE,
1223+
null,
1224+
EditorInfo.IME_ACTION_NONE,
1225+
null,
1226+
null,
1227+
null,
1228+
null));
1229+
// There's a pending restart since we initialized the text input client. Flush that now.
1230+
textInputPlugin.setTextInputEditingState(
1231+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
1232+
assertEquals(1, testImm.getRestartCount(testView));
1233+
1234+
// A restart should be forced when calling clearTextInputClient() and input action is
1235+
// EditorInfo.IME_ACTION_NONE.
1236+
textInputPlugin.clearTextInputClient();
1237+
assertEquals(2, testImm.getRestartCount(testView));
1238+
}
1239+
1240+
@Test
1241+
public void clearTextInputClient_doesNotRestartImmWhenInputActionIsNext() {
1242+
// Regression test for https://github.com/flutter/flutter/issues/148673.
1243+
// Initialize a general TextInputPlugin.
1244+
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
1245+
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
1246+
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
1247+
View testView = new View(ctx);
1248+
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
1249+
TextInputPlugin textInputPlugin =
1250+
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1251+
textInputPlugin.setTextInputClient(
1252+
0,
1253+
new TextInputChannel.Configuration(
1254+
false,
1255+
false,
1256+
true,
1257+
true,
1258+
false,
1259+
TextInputChannel.TextCapitalization.NONE,
1260+
null,
1261+
EditorInfo.IME_ACTION_NEXT,
1262+
null,
1263+
null,
1264+
null,
1265+
null));
1266+
// There's a pending restart since we initialized the text input client. Flush that now.
1267+
textInputPlugin.setTextInputEditingState(
1268+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
1269+
assertEquals(1, testImm.getRestartCount(testView));
1270+
1271+
// No restart is forced when calling clearTextInputClient() and input action is
1272+
// EditorInfo.IME_ACTION_NEXT.
1273+
textInputPlugin.clearTextInputClient();
1274+
assertEquals(1, testImm.getRestartCount(testView));
1275+
}
1276+
11681277
@Test
11691278
public void destroy_clearTextInputMethodHandler() {
11701279
View testView = new View(ctx);

0 commit comments

Comments
 (0)