diff --git a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java index d1b58039fb910..a990ff386108e 100644 --- a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java +++ b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java @@ -16,6 +16,7 @@ import android.text.Layout; import android.text.Selection; import android.text.TextPaint; +import android.text.method.TextKeyListener; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.BaseInputConnection; @@ -321,35 +322,11 @@ public boolean sendKeyEvent(KeyEvent event) { updateEditingState(); return true; } else if (selStart > 0) { - // Delete to the left/right of the cursor depending on direction of text. - // TODO(garyq): Explore how to obtain per-character direction. The - // isRTLCharAt() call below is returning blanket direction assumption - // based on the first character in the line. - boolean isRtl = mLayout.isRtlCharAt(mLayout.getLineForOffset(selStart)); - try { - if (isRtl) { - Selection.extendRight(mEditable, mLayout); - } else { - Selection.extendLeft(mEditable, mLayout); - } - } catch (IndexOutOfBoundsException e) { - // On some Chinese devices (primarily Huawei, some Xiaomi), - // on initial app startup before focus is lost, the - // Selection.extendLeft and extendRight calls always extend - // from the index of the initial contents of mEditable. This - // try-catch will prevent crashing on Huawei devices by falling - // back to a simple way of deletion, although this a hack and - // will not handle emojis. - Selection.setSelection(mEditable, selStart, selStart - 1); + if (TextKeyListener.getInstance().onKeyDown(null, mEditable, event.getKeyCode(), event)) { + updateEditingState(); + return true; } - int newStart = clampIndexToEditable(Selection.getSelectionStart(mEditable), mEditable); - int newEnd = clampIndexToEditable(Selection.getSelectionEnd(mEditable), mEditable); - Selection.setSelection(mEditable, Math.min(newStart, newEnd)); - // Min/Max the values since RTL selections will start at a higher - // index than they end at. - mEditable.delete(Math.min(newStart, newEnd), Math.max(newStart, newEnd)); - updateEditingState(); - return true; + return false; } } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { int selStart = Selection.getSelectionStart(mEditable); 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 bf0f513a0835e..bbca2464a6232 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java @@ -313,15 +313,44 @@ public void inputConnectionAdaptor_RepeatFilter() throws NullPointerException { assertEquals(textInputChannel.selectionEnd, 4); } + @Test + public void testSendKeyEvent_delKeyDeletesBackward() { + int selStart = 29; + Editable editable = sampleRtlEditable(selStart, selStart); + InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable); + + KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); + + for (int i = 0; i < 9; 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); + } + private static final String SAMPLE_TEXT = "Lorem ipsum dolor sit amet," + "\nconsectetur adipiscing elit."; + private static final String SAMPLE_RTL_TEXT = "متن ساختگی" + "\nبرای تستfor test😊"; + private static Editable sampleEditable(int selStart, int selEnd) { SpannableStringBuilder sample = new SpannableStringBuilder(SAMPLE_TEXT); Selection.setSelection(sample, selStart, selEnd); return sample; } + private static Editable sampleRtlEditable(int selStart, int selEnd) { + SpannableStringBuilder sample = new SpannableStringBuilder(SAMPLE_RTL_TEXT); + Selection.setSelection(sample, selStart, selEnd); + return sample; + } + private static InputConnectionAdaptor sampleInputConnectionAdaptor(Editable editable) { View testView = new View(RuntimeEnvironment.application); int client = 0;