From b4d4e30c0a9c9d6ba3e3b99e43fd161d235894cb Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Fri, 20 Nov 2020 10:43:02 -0800 Subject: [PATCH] Fix double delete on backspace on Android (#22626) --- .../editing/InputConnectionAdaptor.java | 16 +- .../editing/InputConnectionAdaptorTest.java | 156 +----------------- 2 files changed, 5 insertions(+), 167 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java index 7615126b135e22..eceadf91dc837e 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 @@ public boolean sendKeyEvent(KeyEvent event) { } 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 feec49b017e756..dfab9ecbe0db3a 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 @@ public void testCursorAnchorInfo() { } @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); - } - 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); + assertFalse(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