[Android] Fix TextInputType.none for devices with physical keyboard (flutter/engine#49980)

## Description

This PR fixes an issue where keystrokes aren't received on Android
devices with physical keyboards (e.g. rugged Zebra devices) when
`keyboardType` is set to `TextInputType.none` on a `TextField`.

The logic in `setTextInputClient` and `canShowTextInput` created an
`inputTarget` with `InputTarget.Type.NO_TARGET` which caused the [input
connection to short
circuit](https://github.com/flutter/engine/blob/main/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java#L296)
and not be established.

Bug introduction PR: https://github.com/flutter/engine/pull/26585

## Related Issue

https://github.com/flutter/flutter/issues/89983

## Unit Test Notes

- The existing `showTextInput_textInputTypeNone()` stays green after
update.
- `inputConnection_textInputTypeNone()` updated to `assertNotNull`. I
would make this more specific, but this is my first venture into the
Flutter engine and don't know enough about those connection attributes.

## Demo

Video below with Zebra MC9300 device. This issue can also be reproduced
in a standard android emulator. Simply add a `TextField`, configure
`keyboardType` to be `TextInputType.none` and attempt to enter text
after running and giving focus to textfield.

Before


https://github.com/flutter/engine/assets/1988098/348ca061-b8b9-4483-956e-0732c1238207

After


https://github.com/flutter/engine/assets/1988098/b65c7251-59b4-4c73-9b85-7ac03f47a7e4

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [ ] I added new tests to check the change I am making or feature I am
adding, or the PR is [test-exempt]. See [testing the engine] for
instructions on writing and running engine tests.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [x] I signed the [CLA].
- [x] All existing and new tests are passing.
This commit is contained in:
Bart Cone
2024-02-02 02:24:39 -05:00
committed by GitHub
parent 64fe7b86c3
commit 1b95fed6c0
2 changed files with 19 additions and 17 deletions

View File

@@ -376,16 +376,11 @@ public class TextInputPlugin implements ListenableEditingState.EditingStateWatch
mImm.sendAppPrivateCommand(mView, action, data);
}
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()) {
if (configuration == null
|| configuration.inputType == null
|| configuration.inputType.type != TextInputChannel.TextInputType.NONE) {
view.requestFocus();
mImm.showSoftInput(view, 0);
} else {
@@ -409,11 +404,7 @@ public class TextInputPlugin implements ListenableEditingState.EditingStateWatch
// Call notifyViewExited on the previous field.
notifyViewExited();
this.configuration = configuration;
if (canShowTextInput()) {
inputTarget = new InputTarget(InputTarget.Type.FRAMEWORK_CLIENT, client);
} else {
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, client);
}
inputTarget = new InputTarget(InputTarget.Type.FRAMEWORK_CLIENT, client);
mEditable.removeEditingStateListener(this);
mEditable =

View File

@@ -1,6 +1,7 @@
package io.flutter.plugin.editing;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
@@ -1176,8 +1177,8 @@ public class TextInputPluginTest {
@SuppressWarnings("deprecation")
// DartExecutor.send is deprecated.
@Test
public void inputConnection_createsActionFromEnter() throws JSONException {
private void verifyInputConnection(TextInputChannel.TextInputType textInputType)
throws JSONException {
TestImm testImm = Shadow.extract(ctx.getSystemService(Context.INPUT_METHOD_SERVICE));
FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
View testView = new View(ctx);
@@ -1194,7 +1195,7 @@ public class TextInputPluginTest {
true,
false,
TextInputChannel.TextCapitalization.NONE,
new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT, false, false),
new TextInputChannel.InputType(textInputType, false, false),
null,
null,
null,
@@ -1232,6 +1233,16 @@ public class TextInputPluginTest {
new String[] {"0", "TextInputAction.done"});
}
@Test
public void inputConnection_createsActionFromEnter() throws JSONException {
verifyInputConnection(TextInputChannel.TextInputType.TEXT);
}
@Test
public void inputConnection_respondsToKeyEvents_textInputTypeNone() throws JSONException {
verifyInputConnection(TextInputChannel.TextInputType.NONE);
}
@SuppressWarnings("deprecation") // InputMethodSubtype
@Test
public void inputConnection_finishComposingTextUpdatesIMM() throws JSONException {
@@ -1310,7 +1321,7 @@ public class TextInputPluginTest {
InputConnection connection =
textInputPlugin.createInputConnection(
testView, mock(KeyboardManager.class), new EditorInfo());
assertEquals(connection, null);
assertNotNull(connection);
}
@Test