Fix double delete on backspace on Android (#22626) (#22678)
Co-authored-by: Greg Spencer <gspencergoog@users.noreply.github.com>
diff --git a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java
index 7615126..eceadf9 100644
--- a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java
+++ b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java
@@ -296,21 +296,7 @@
}
if (event.getAction() == KeyEvent.ACTION_DOWN) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
- int selStart = clampIndexToEditable(Selection.getSelectionStart(mEditable), mEditable);
- int selEnd = clampIndexToEditable(Selection.getSelectionEnd(mEditable), mEditable);
- if (selStart == selEnd && selStart > 0) {
- // Extend selection to left of the last character
- selStart = flutterTextUtils.getOffsetBefore(mEditable, selStart);
- }
- if (selEnd > selStart) {
- // Delete the selection.
- Selection.setSelection(mEditable, selStart);
- mEditable.delete(selStart, selEnd);
- return true;
- }
- return false;
- } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
int selStart = Selection.getSelectionStart(mEditable);
int selEnd = Selection.getSelectionEnd(mEditable);
if (selStart == selEnd && !event.isShiftPressed()) {
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 feec49b..dfab9ec 100644
--- a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java
+++ b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java
@@ -1029,166 +1029,18 @@
}
@Test
- public void testSendKeyEvent_delKeyDeletesBackward() {
+ public void testSendKeyEvent_delKeyNotConsumed() {
int selStart = 29;
ListenableEditingState editable = sampleEditable(selStart, selStart, SAMPLE_RTL_TEXT);
InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable);
KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
- for (int i = 0; i < 9; i++) {
+ for (int i = 0; i < 10; i++) {
boolean didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
+ assertFalse(didConsume);
}
- assertEquals(Selection.getSelectionStart(editable), 19);
-
- for (int i = 0; i < 9; i++) {
- boolean didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- }
- assertEquals(Selection.getSelectionStart(editable), 10);
- }
-
- @Test
- public void testSendKeyEvent_delKeyDeletesBackwardComplexEmojis() {
- int selStart = 75;
- ListenableEditingState editable = sampleEditable(selStart, selStart, SAMPLE_EMOJI_TEXT);
- InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable);
-
- KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
- boolean didConsume;
-
- // Normal Character
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 74);
-
- // Non-Spacing Mark
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 73);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 72);
-
- // Keycap
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 69);
-
- // Keycap with invalid base
- adaptor.setSelection(68, 68);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 66);
- adaptor.setSelection(67, 67);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 66);
-
- // Zero Width Joiner
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 55);
-
- // Zero Width Joiner with invalid base
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 53);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 52);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 51);
-
- // ----- Start Emoji Tag Sequence with invalid base testing ----
- // Delete base tag
- adaptor.setSelection(39, 39);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 37);
-
- // Delete the sequence
- adaptor.setSelection(49, 49);
- for (int i = 0; i < 6; i++) {
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- }
- assertEquals(Selection.getSelectionStart(editable), 37);
- // ----- End Emoji Tag Sequence with invalid base testing ----
-
- // Emoji Tag Sequence
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 23);
-
- // Variation Selector with invalid base
- adaptor.setSelection(22, 22);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 21);
- adaptor.setSelection(22, 22);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 21);
-
- // Variation Selector
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 19);
-
- // Emoji Modifier
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 16);
-
- // Emoji Modifier with invalid base
- adaptor.setSelection(14, 14);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 13);
- adaptor.setSelection(14, 14);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 13);
-
- // Line Feed
- adaptor.setSelection(12, 12);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 11);
-
- // Carriage Return
- adaptor.setSelection(12, 12);
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 11);
-
- // Carriage Return and Line Feed
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 9);
-
- // Regional Indicator Symbol odd
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 7);
-
- // Regional Indicator Symbol even
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 3);
-
- // Simple Emoji
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 1);
-
- // First CodePoint
- didConsume = adaptor.sendKeyEvent(downKeyDown);
- assertTrue(didConsume);
- assertEquals(Selection.getSelectionStart(editable), 0);
+ assertEquals(29, Selection.getSelectionStart(editable));
}
@Test