From 8c77cbc8ab62208fd2044766bb3c02169a32ed6a Mon Sep 17 00:00:00 2001 From: weiguoliang Date: Tue, 22 Feb 2022 18:35:29 +0800 Subject: [PATCH] Android Input Failed When TextInputType Is Phone, Number --- .../editing/InputConnectionAdaptor.java | 22 +++++++++++-- .../editing/InputConnectionAdaptorTest.java | 33 +++++++++++++++++-- .../test/io/flutter/util/FakeKeyEvent.java | 21 +++++++++++- 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java index d3528a9ccc79d..936d0c015e8b2 100644 --- a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java +++ b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java @@ -287,6 +287,8 @@ public boolean handleKeyEvent(KeyEvent event) { return handleVerticalMovement(false, event.isShiftPressed()); // When the enter key is pressed on a non-multiline field, consider it a // submit instead of a newline. + } else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) { + return handleDelete(); } else if ((event.getKeyCode() == KeyEvent.KEYCODE_ENTER || event.getKeyCode() == KeyEvent.KEYCODE_NUMPAD_ENTER) && (InputType.TYPE_TEXT_FLAG_MULTI_LINE & mEditorInfo.inputType) == 0) { @@ -297,12 +299,12 @@ public boolean handleKeyEvent(KeyEvent event) { final int selStart = Selection.getSelectionStart(mEditable); final int selEnd = Selection.getSelectionEnd(mEditable); final int character = event.getUnicodeChar(); - if (selStart < 0 || selEnd < 0 || character == 0) { + if (character == 0) { return false; } - final int selMin = Math.min(selStart, selEnd); - final int selMax = Math.max(selStart, selEnd); + final int selMin = Math.max(Math.min(selStart, selEnd), 0); + final int selMax = Math.max(Math.max(selStart, selEnd), 0); beginBatchEdit(); if (selMin != selMax) mEditable.delete(selMin, selMax); mEditable.insert(selMin, String.valueOf((char) character)); @@ -375,6 +377,20 @@ private boolean handleVerticalMovement(boolean isUp, boolean isShiftPressed) { return true; } + private boolean handleDelete() { + final int selStart = Selection.getSelectionStart(mEditable); + final int selEnd = Selection.getSelectionEnd(mEditable); + + if (selStart <= 0 || selEnd <= 0) { + return false; + } + beginBatchEdit(); + mEditable.delete(selStart - 1, selEnd); + setSelection(selStart - 1, selEnd - 1); + endBatchEdit(); + return true; + } + @Override public boolean performContextMenuAction(int id) { beginBatchEdit(); diff --git a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java index 3b3d35dc82c72..89cac2845355d 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java @@ -43,6 +43,8 @@ import io.flutter.plugin.common.MethodCall; import io.flutter.util.FakeKeyEvent; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.junit.Before; @@ -1104,16 +1106,25 @@ public void testSendKeyEvent_sendHardwareKeyEvents() { @Test public void testSendKeyEvent_delKeyNotConsumed() { - ListenableEditingState editable = sampleEditable(5, 5); + ListenableEditingState editable = sampleEditable(5, 5, "01234"); InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable); - KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); + KeyEvent downKeyUP = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL); for (int i = 0; i < 4; i++) { - boolean didConsume = adaptor.handleKeyEvent(downKeyDown); + boolean didConsume = adaptor.handleKeyEvent(downKeyUP); assertFalse(didConsume); } assertEquals(5, Selection.getSelectionStart(editable)); + + // delete character + KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); + for (int i = 0; i < 5; i++) { + boolean didConsume = adaptor.handleKeyEvent(downKeyDown); + assertTrue(didConsume); + } + assertEquals(0, Selection.getSelectionStart(editable)); + assertEquals("", editable.toString()); } @Test @@ -1127,6 +1138,22 @@ public void testDoesNotConsumeBackButton() { assertFalse(didConsume); } + @Test + public void testInputKeycode() { + ListenableEditingState editable = sampleEditable(0, 0, ""); + InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable); + + List keyEvents = new ArrayList<>(); + keyEvents.add(new FakeKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_1)); + keyEvents.add(new FakeKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_2)); + keyEvents.add(new FakeKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_3)); + + for (FakeKeyEvent keyEvent : keyEvents) { + adaptor.handleKeyEvent(keyEvent); + } + assertEquals("123", editable.toString()); + } + @Test public void testCleanUpBatchEndsOnCloseConnection() { final ListenableEditingState editable = sampleEditable(0, 0); diff --git a/shell/platform/android/test/io/flutter/util/FakeKeyEvent.java b/shell/platform/android/test/io/flutter/util/FakeKeyEvent.java index 75ce7b6ddb302..ce5c187f13813 100644 --- a/shell/platform/android/test/io/flutter/util/FakeKeyEvent.java +++ b/shell/platform/android/test/io/flutter/util/FakeKeyEvent.java @@ -1,18 +1,37 @@ package io.flutter.util; import android.view.KeyEvent; +import java.util.HashMap; +import java.util.Map; // In the test environment, keyEvent.getUnicodeChar throws an exception. This // class works around the exception by hardcoding the returned value. public class FakeKeyEvent extends KeyEvent { + + private Map keyCodeMap = new HashMap<>(); + public FakeKeyEvent(int action, int keyCode) { super(action, keyCode); + keyCodeMap.put(KEYCODE_1, (int) '1'); + keyCodeMap.put(KEYCODE_2, (int) '2'); + keyCodeMap.put(KEYCODE_3, (int) '3'); + keyCodeMap.put(KEYCODE_4, (int) '4'); + keyCodeMap.put(KEYCODE_5, (int) '5'); + keyCodeMap.put(KEYCODE_6, (int) '6'); + keyCodeMap.put(KEYCODE_7, (int) '7'); + keyCodeMap.put(KEYCODE_8, (int) '8'); + keyCodeMap.put(KEYCODE_9, (int) '9'); + keyCodeMap.put(KEYCODE_0, (int) '0'); } public final int getUnicodeChar() { - if (getKeyCode() == KeyEvent.KEYCODE_BACK) { + int code = getKeyCode(); + if (code == KeyEvent.KEYCODE_BACK) { return 0; } + if (keyCodeMap.containsKey(code)) { + return keyCodeMap.get(code); + } return 1; } }