diff options
3 files changed, 55 insertions, 13 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 5816e5680..c548f1145 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -680,7 +680,7 @@ public class Keyboard { a.recycle(); if (resourceId == 0) { if (LatinImeLogger.sDBG) - throw new RuntimeException("touchPositionCorrectionData is not defined"); + Log.e(TAG, "touchPositionCorrectionData is not defined"); return; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a053b9bbb..31cbc4ee3 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -203,9 +203,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private WordComposer mWordComposer = new WordComposer(); private int mCorrectionMode; + // Keep track of the last selection range to decide if we need to show word alternatives - private int mLastSelectionStart; - private int mLastSelectionEnd; + private static final int NOT_A_CURSOR_POSITION = -1; + private int mLastSelectionStart = NOT_A_CURSOR_POSITION; + private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't // "expect" it, it means the user actually moved the cursor. @@ -1401,9 +1403,29 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // inconsistent with backspacing after selecting other suggestions. restartSuggestionsOnManuallyPickedTypedWord(ic); } else { - ic.deleteSurroundingText(1, 0); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - ic.deleteSurroundingText(1, 0); + // Here we must check whether there is a selection. If so we should remove the + // selected text, otherwise we should just delete the character before the cursor. + if (mLastSelectionStart != mLastSelectionEnd) { + final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; + ic.setSelection(mLastSelectionEnd, mLastSelectionEnd); + ic.deleteSurroundingText(lengthToDelete, 0); + } else { + if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { + // We don't know whether there is a selection or not. We just send a false + // hardware key event and let TextView sort it out for us. The problem + // here is, this is asynchronous with respect to the input connection + // batch edit, so it may flicker. But this only ever happens if backspace + // is pressed just after the IME is invoked, and then again only once. + // TODO: add an API call that gets the selection indices. This is available + // to the IME in the general case via onUpdateSelection anyway, and would + // allow us to remove this race condition. + sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + } else { + ic.deleteSurroundingText(1, 0); + } + if (mDeleteCount > DELETE_ACCELERATE_AT) { + ic.deleteSurroundingText(1, 0); + } } if (isSuggestionsRequested()) { restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 06ee5bffa..0d5e42b81 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -41,6 +41,7 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> { private LatinIME mLatinIME; private TextView mTextView; + private InputConnection mInputConnection; public InputLogicTests() { super(LatinIME.class); @@ -82,6 +83,7 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> { mLatinIME.onCreateInputView(); mLatinIME.onStartInputView(ei, false); mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); + mInputConnection = ic; } // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME. @@ -106,17 +108,35 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> { } public void testTypeWord() { - final String wordToType = "abcd"; - type(wordToType); - assertEquals("type word", wordToType, mTextView.getText().toString()); + final String WORD_TO_TYPE = "abcd"; + type(WORD_TO_TYPE); + assertEquals("type word", WORD_TO_TYPE, mTextView.getText().toString()); } public void testPickSuggestionThenBackspace() { - final String wordToType = "tgis"; - type(wordToType); - mLatinIME.pickSuggestionManually(0, wordToType); + final String WORD_TO_TYPE = "tgis"; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); type(Keyboard.CODE_DELETE); - assertEquals("press suggestion then backspace", wordToType, mTextView.getText().toString()); + assertEquals("press suggestion then backspace", WORD_TO_TYPE, + mTextView.getText().toString()); } + public void testDeleteSelection() { + final String STRING_TO_TYPE = "some text delete me some text"; + final int SELECTION_START = 10; + final int SELECTION_END = 19; + final String EXPECTED_RESULT = "some text some text"; + type(STRING_TO_TYPE); + // There is no IMF to call onUpdateSelection for us so we must do it by hand. + // Send once to simulate the cursor actually responding to the move caused by typing. + // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor + // move with a move triggered by LatinIME inputting stuff. + mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); + mInputConnection.setSelection(SELECTION_START, SELECTION_END); + // And now we simulate the user actually selecting some text. + mLatinIME.onUpdateSelection(0, 0, SELECTION_START, SELECTION_END, -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("delete selection", EXPECTED_RESULT, mTextView.getText().toString()); + } } |