diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index 4897eaf2f13cd..b4ce4726e8c51 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -569,6 +569,10 @@ void clearTextInputClient() { inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0); unlockPlatformViewInputConnection(); lastClientRect = null; + + // Call restartInput to reset IME internal states. Otherwise some IMEs (Gboard for instance) + // keep reacting based on the previous input configuration until a new configuration is set. + mImm.restartInput(mView); } private static class InputTarget { diff --git a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java index c4eebd33b939d..13f5506838b02 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java @@ -1128,6 +1128,41 @@ public void setTextInputEditingState_nullInputMethodSubtype() { assertEquals(1, testImm.getRestartCount(testView)); } + @Test + public void clearTextInputClient_alwaysRestartsImm() { + // 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, + null, + 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 is always forced when calling clearTextInputClient(). + textInputPlugin.clearTextInputClient(); + assertEquals(2, testImm.getRestartCount(testView)); + } + @Test public void destroy_clearTextInputMethodHandler() { View testView = new View(ctx);