Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6b883e9

Browse files
Fix RTL handling in delete key event for android (#17393)
1 parent 6e1d7f8 commit 6b883e9

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed

shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import android.text.Layout;
1717
import android.text.Selection;
1818
import android.text.TextPaint;
19+
import android.text.method.TextKeyListener;
1920
import android.view.KeyEvent;
2021
import android.view.View;
2122
import android.view.inputmethod.BaseInputConnection;
@@ -321,35 +322,11 @@ public boolean sendKeyEvent(KeyEvent event) {
321322
updateEditingState();
322323
return true;
323324
} else if (selStart > 0) {
324-
// Delete to the left/right of the cursor depending on direction of text.
325-
// TODO(garyq): Explore how to obtain per-character direction. The
326-
// isRTLCharAt() call below is returning blanket direction assumption
327-
// based on the first character in the line.
328-
boolean isRtl = mLayout.isRtlCharAt(mLayout.getLineForOffset(selStart));
329-
try {
330-
if (isRtl) {
331-
Selection.extendRight(mEditable, mLayout);
332-
} else {
333-
Selection.extendLeft(mEditable, mLayout);
334-
}
335-
} catch (IndexOutOfBoundsException e) {
336-
// On some Chinese devices (primarily Huawei, some Xiaomi),
337-
// on initial app startup before focus is lost, the
338-
// Selection.extendLeft and extendRight calls always extend
339-
// from the index of the initial contents of mEditable. This
340-
// try-catch will prevent crashing on Huawei devices by falling
341-
// back to a simple way of deletion, although this a hack and
342-
// will not handle emojis.
343-
Selection.setSelection(mEditable, selStart, selStart - 1);
325+
if (TextKeyListener.getInstance().onKeyDown(null, mEditable, event.getKeyCode(), event)) {
326+
updateEditingState();
327+
return true;
344328
}
345-
int newStart = clampIndexToEditable(Selection.getSelectionStart(mEditable), mEditable);
346-
int newEnd = clampIndexToEditable(Selection.getSelectionEnd(mEditable), mEditable);
347-
Selection.setSelection(mEditable, Math.min(newStart, newEnd));
348-
// Min/Max the values since RTL selections will start at a higher
349-
// index than they end at.
350-
mEditable.delete(Math.min(newStart, newEnd), Math.max(newStart, newEnd));
351-
updateEditingState();
352-
return true;
329+
return false;
353330
}
354331
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
355332
int selStart = Selection.getSelectionStart(mEditable);

shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,15 +313,44 @@ public void inputConnectionAdaptor_RepeatFilter() throws NullPointerException {
313313
assertEquals(textInputChannel.selectionEnd, 4);
314314
}
315315

316+
@Test
317+
public void testSendKeyEvent_delKeyDeletesBackward() {
318+
int selStart = 29;
319+
Editable editable = sampleRtlEditable(selStart, selStart);
320+
InputConnectionAdaptor adaptor = sampleInputConnectionAdaptor(editable);
321+
322+
KeyEvent downKeyDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
323+
324+
for (int i = 0; i < 9; i++) {
325+
boolean didConsume = adaptor.sendKeyEvent(downKeyDown);
326+
assertTrue(didConsume);
327+
}
328+
assertEquals(Selection.getSelectionStart(editable), 19);
329+
330+
for (int i = 0; i < 9; i++) {
331+
boolean didConsume = adaptor.sendKeyEvent(downKeyDown);
332+
assertTrue(didConsume);
333+
}
334+
assertEquals(Selection.getSelectionStart(editable), 10);
335+
}
336+
316337
private static final String SAMPLE_TEXT =
317338
"Lorem ipsum dolor sit amet," + "\nconsectetur adipiscing elit.";
318339

340+
private static final String SAMPLE_RTL_TEXT = "متن ساختگی" + "\nبرای تستfor test😊";
341+
319342
private static Editable sampleEditable(int selStart, int selEnd) {
320343
SpannableStringBuilder sample = new SpannableStringBuilder(SAMPLE_TEXT);
321344
Selection.setSelection(sample, selStart, selEnd);
322345
return sample;
323346
}
324347

348+
private static Editable sampleRtlEditable(int selStart, int selEnd) {
349+
SpannableStringBuilder sample = new SpannableStringBuilder(SAMPLE_RTL_TEXT);
350+
Selection.setSelection(sample, selStart, selEnd);
351+
return sample;
352+
}
353+
325354
private static InputConnectionAdaptor sampleInputConnectionAdaptor(Editable editable) {
326355
View testView = new View(RuntimeEnvironment.application);
327356
int client = 0;

0 commit comments

Comments
 (0)