diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java index c42a9d2d3d304..79c8191079980 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java @@ -640,7 +640,8 @@ public enum TextInputType { MULTILINE("TextInputType.multiline"), EMAIL_ADDRESS("TextInputType.emailAddress"), URL("TextInputType.url"), - VISIBLE_PASSWORD("TextInputType.visiblePassword"); + VISIBLE_PASSWORD("TextInputType.visiblePassword"), + NONE("TextInputType.none"); static TextInputType fromValue(@NonNull String encodedName) throws NoSuchFieldException { for (TextInputType textInputType : TextInputType.values()) { diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index c07f92462ca71..cd1e385d1b5bd 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -244,6 +244,8 @@ private static int inputTypeFromTextInputType( return textType; } else if (type.type == TextInputChannel.TextInputType.PHONE) { return InputType.TYPE_CLASS_PHONE; + } else if (type.type == TextInputChannel.TextInputType.NONE) { + return InputType.TYPE_NULL; } int textType = InputType.TYPE_CLASS_TEXT; @@ -365,9 +367,21 @@ public void sendTextInputAppPrivateCommand(String action, Bundle data) { mImm.sendAppPrivateCommand(mView, action, data); } - private void showTextInput(View view) { - view.requestFocus(); - mImm.showSoftInput(view, 0); + private boolean canShowTextInput() { + if (configuration == null || configuration.inputType == null) { + return true; + } + return configuration.inputType.type != TextInputChannel.TextInputType.NONE; + } + + @VisibleForTesting + void showTextInput(View view) { + if (canShowTextInput()) { + view.requestFocus(); + mImm.showSoftInput(view, 0); + } else { + hideTextInput(view); + } } private void hideTextInput(View view) { @@ -385,7 +399,12 @@ private void hideTextInput(View view) { void setTextInputClient(int client, TextInputChannel.Configuration configuration) { // Call notifyViewExited on the previous field. notifyViewExited(); - inputTarget = new InputTarget(InputTarget.Type.FRAMEWORK_CLIENT, client); + this.configuration = configuration; + if (canShowTextInput()) { + inputTarget = new InputTarget(InputTarget.Type.FRAMEWORK_CLIENT, client); + } else { + inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, client); + } if (mEditable != null) { mEditable.removeEditingStateListener(this); @@ -393,7 +412,6 @@ void setTextInputClient(int client, TextInputChannel.Configuration configuration mEditable = new ListenableEditingState( configuration.autofill != null ? configuration.autofill.editState : null, mView); - this.configuration = configuration; updateAutofillConfigurationIfNeeded(configuration); // setTextInputClient will be followed by a call to setTextInputEditingState. 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 972d41236e95b..acf1d4fe7c790 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java @@ -604,6 +604,59 @@ public void inputConnection_finishComposingTextUpdatesIMM() throws JSONException assertEquals(0, testImm.getLastCursorAnchorInfo().getComposingText().length()); } + @Test + public void inputConnection_textInputTypeNone() { + View testView = new View(RuntimeEnvironment.application); + DartExecutor dartExecutor = mock(DartExecutor.class); + TextInputChannel textInputChannel = new TextInputChannel(dartExecutor); + TextInputPlugin textInputPlugin = + new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class)); + textInputPlugin.setTextInputClient( + 0, + new TextInputChannel.Configuration( + false, + false, + true, + TextInputChannel.TextCapitalization.NONE, + new TextInputChannel.InputType(TextInputChannel.TextInputType.NONE, false, false), + null, + null, + null, + null)); + + InputConnection connection = + textInputPlugin.createInputConnection( + testView, mock(KeyboardManager.class), new EditorInfo()); + assertEquals(connection, null); + } + + @Test + public void showTextInput_textInputTypeNone() { + TestImm testImm = + Shadow.extract( + RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE)); + View testView = new View(RuntimeEnvironment.application); + DartExecutor dartExecutor = mock(DartExecutor.class); + TextInputChannel textInputChannel = new TextInputChannel(dartExecutor); + TextInputPlugin textInputPlugin = + new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class)); + textInputPlugin.setTextInputClient( + 0, + new TextInputChannel.Configuration( + false, + false, + true, + TextInputChannel.TextCapitalization.NONE, + new TextInputChannel.InputType(TextInputChannel.TextInputType.NONE, false, false), + null, + null, + null, + null)); + + textInputPlugin.showTextInput(testView); + assertEquals(testImm.isSoftInputVisible(), false); + } + // -------- Start: Autofill Tests ------- @Test public void autofill_onProvideVirtualViewStructure() {