[Android] Call restartInput selectively on clear (flutter/engine#53662)
## Description This PR restricts the call to `restartInput` which was added in https://github.com/flutter/engine/pull/49829. The restart is called when input action is null, DONE, or NONE. ## Related Issue Fixes https://github.com/flutter/flutter/issues/148673. ## Tests Updates 1 test, adds 3 tests.
This commit is contained in:
parent
21df44f8b0
commit
42ec2e55c5
@ -546,15 +546,22 @@ public class TextInputPlugin implements ListenableEditingState.EditingStateWatch
|
|||||||
}
|
}
|
||||||
mEditable.removeEditingStateListener(this);
|
mEditable.removeEditingStateListener(this);
|
||||||
notifyViewExited();
|
notifyViewExited();
|
||||||
|
|
||||||
|
boolean needsRestart =
|
||||||
|
configuration.inputAction == null
|
||||||
|
|| configuration.inputAction == EditorInfo.IME_ACTION_DONE
|
||||||
|
|| configuration.inputAction == EditorInfo.IME_ACTION_NONE;
|
||||||
configuration = null;
|
configuration = null;
|
||||||
updateAutofillConfigurationIfNeeded(null);
|
updateAutofillConfigurationIfNeeded(null);
|
||||||
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
|
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
|
||||||
unlockPlatformViewInputConnection();
|
unlockPlatformViewInputConnection();
|
||||||
lastClientRect = null;
|
lastClientRect = null;
|
||||||
|
|
||||||
// Call restartInput to reset IME internal states. Otherwise some IMEs (Gboard for instance)
|
if (needsRestart) {
|
||||||
// keep reacting based on the previous input configuration until a new configuration is set.
|
// Call restartInput to reset IME internal states. Otherwise some IMEs (Gboard for instance)
|
||||||
mImm.restartInput(mView);
|
// keep reacting based on the previous input configuration until a new configuration is set.
|
||||||
|
mImm.restartInput(mView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class InputTarget {
|
private static class InputTarget {
|
||||||
|
@ -1131,7 +1131,7 @@ public class TextInputPluginTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void clearTextInputClient_alwaysRestartsImm() {
|
public void clearTextInputClient_restartsImmWhenInputActionIsNull() {
|
||||||
// Initialize a general TextInputPlugin.
|
// Initialize a general TextInputPlugin.
|
||||||
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
|
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
|
||||||
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
|
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
|
||||||
@ -1165,6 +1165,115 @@ public class TextInputPluginTest {
|
|||||||
assertEquals(2, testImm.getRestartCount(testView));
|
assertEquals(2, testImm.getRestartCount(testView));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearTextInputClient_restartsImmWhenInputActionIsDone() {
|
||||||
|
// Initialize a general TextInputPlugin.
|
||||||
|
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
|
||||||
|
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
|
||||||
|
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
|
||||||
|
View testView = new View(ctx);
|
||||||
|
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
|
||||||
|
TextInputPlugin textInputPlugin =
|
||||||
|
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
|
||||||
|
textInputPlugin.setTextInputClient(
|
||||||
|
0,
|
||||||
|
new TextInputChannel.Configuration(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
TextInputChannel.TextCapitalization.NONE,
|
||||||
|
null,
|
||||||
|
EditorInfo.IME_ACTION_DONE,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null));
|
||||||
|
// There's a pending restart since we initialized the text input client. Flush that now.
|
||||||
|
textInputPlugin.setTextInputEditingState(
|
||||||
|
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
|
||||||
|
assertEquals(1, testImm.getRestartCount(testView));
|
||||||
|
|
||||||
|
// A restart should be forced when calling clearTextInputClient() and input action is
|
||||||
|
// EditorInfo.IME_ACTION_DONE.
|
||||||
|
textInputPlugin.clearTextInputClient();
|
||||||
|
assertEquals(2, testImm.getRestartCount(testView));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearTextInputClient_restartsImmWhenInputActionIsNone() {
|
||||||
|
// Initialize a general TextInputPlugin.
|
||||||
|
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
|
||||||
|
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
|
||||||
|
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
|
||||||
|
View testView = new View(ctx);
|
||||||
|
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
|
||||||
|
TextInputPlugin textInputPlugin =
|
||||||
|
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
|
||||||
|
textInputPlugin.setTextInputClient(
|
||||||
|
0,
|
||||||
|
new TextInputChannel.Configuration(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
TextInputChannel.TextCapitalization.NONE,
|
||||||
|
null,
|
||||||
|
EditorInfo.IME_ACTION_NONE,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null));
|
||||||
|
// There's a pending restart since we initialized the text input client. Flush that now.
|
||||||
|
textInputPlugin.setTextInputEditingState(
|
||||||
|
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
|
||||||
|
assertEquals(1, testImm.getRestartCount(testView));
|
||||||
|
|
||||||
|
// A restart should be forced when calling clearTextInputClient() and input action is
|
||||||
|
// EditorInfo.IME_ACTION_NONE.
|
||||||
|
textInputPlugin.clearTextInputClient();
|
||||||
|
assertEquals(2, testImm.getRestartCount(testView));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearTextInputClient_doesNotRestartImmWhenInputActionIsNext() {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/148673.
|
||||||
|
// Initialize a general TextInputPlugin.
|
||||||
|
InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
|
||||||
|
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
|
||||||
|
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
|
||||||
|
View testView = new View(ctx);
|
||||||
|
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
|
||||||
|
TextInputPlugin textInputPlugin =
|
||||||
|
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
|
||||||
|
textInputPlugin.setTextInputClient(
|
||||||
|
0,
|
||||||
|
new TextInputChannel.Configuration(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
TextInputChannel.TextCapitalization.NONE,
|
||||||
|
null,
|
||||||
|
EditorInfo.IME_ACTION_NEXT,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null));
|
||||||
|
// There's a pending restart since we initialized the text input client. Flush that now.
|
||||||
|
textInputPlugin.setTextInputEditingState(
|
||||||
|
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
|
||||||
|
assertEquals(1, testImm.getRestartCount(testView));
|
||||||
|
|
||||||
|
// No restart is forced when calling clearTextInputClient() and input action is
|
||||||
|
// EditorInfo.IME_ACTION_NEXT.
|
||||||
|
textInputPlugin.clearTextInputClient();
|
||||||
|
assertEquals(1, testImm.getRestartCount(testView));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void destroy_clearTextInputMethodHandler() {
|
public void destroy_clearTextInputMethodHandler() {
|
||||||
View testView = new View(ctx);
|
View testView = new View(ctx);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user