Cleanup before fixing getTextAfterCursor().
We never delete text after the cursor, so constrain the API accordingly. Define the number of characters to read before and after. Set them to reasonable values. The next CL will start caching text after the cursor. Bug 21926256. Change-Id: Idd58daf68614de4a69344aa3c8a4323720c5d3a0main
parent
02c28453fc
commit
0232e73dfa
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import static com.android.inputmethod.latin.define.DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH;
|
|
||||||
|
|
||||||
import android.inputmethodservice.InputMethodService;
|
import android.inputmethodservice.InputMethodService;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -37,7 +35,6 @@ import com.android.inputmethod.compat.InputConnectionCompatUtils;
|
||||||
import com.android.inputmethod.latin.common.Constants;
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
import com.android.inputmethod.latin.common.UnicodeSurrogate;
|
import com.android.inputmethod.latin.common.UnicodeSurrogate;
|
||||||
import com.android.inputmethod.latin.common.StringUtils;
|
import com.android.inputmethod.latin.common.StringUtils;
|
||||||
import com.android.inputmethod.latin.define.DecoderSpecificConstants;
|
|
||||||
import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer;
|
import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer;
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
||||||
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
||||||
|
@ -59,14 +56,12 @@ import javax.annotation.Nullable;
|
||||||
* for example.
|
* for example.
|
||||||
*/
|
*/
|
||||||
public final class RichInputConnection implements PrivateCommandPerformer {
|
public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
private static final String TAG = RichInputConnection.class.getSimpleName();
|
private static final String TAG = "RichInputConnection";
|
||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
private static final boolean DEBUG_PREVIOUS_TEXT = false;
|
private static final boolean DEBUG_PREVIOUS_TEXT = false;
|
||||||
private static final boolean DEBUG_BATCH_NESTING = false;
|
private static final boolean DEBUG_BATCH_NESTING = false;
|
||||||
// Provision for realistic N-grams like "Hello, how are you?" and "I'm running 5 late".
|
private static final int NUM_CHARS_TO_GET_BEFORE_CURSOR = 40;
|
||||||
// Technically, this will not handle 5-grams composed of long words, but in practice,
|
private static final int NUM_CHARS_TO_GET_AFTER_CURSOR = 40;
|
||||||
// our language models don't include that much data.
|
|
||||||
private static final int LOOKBACK_CHARACTER_NUM = 80;
|
|
||||||
private static final int INVALID_CURSOR_POSITION = -1;
|
private static final int INVALID_CURSOR_POSITION = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +80,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
private int mExpectedSelEnd = INVALID_CURSOR_POSITION; // in chars, not code points
|
private int mExpectedSelEnd = INVALID_CURSOR_POSITION; // in chars, not code points
|
||||||
/**
|
/**
|
||||||
* This contains the committed text immediately preceding the cursor and the composing
|
* This contains the committed text immediately preceding the cursor and the composing
|
||||||
* text if any. It is refreshed when the cursor moves by calling upon the TextView.
|
* text, if any. It is refreshed when the cursor moves by calling upon the TextView.
|
||||||
*/
|
*/
|
||||||
private final StringBuilder mCommittedTextBeforeComposingText = new StringBuilder();
|
private final StringBuilder mCommittedTextBeforeComposingText = new StringBuilder();
|
||||||
/**
|
/**
|
||||||
|
@ -386,7 +381,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
return isConnected() ? mIC.getTextAfterCursor(n, flags) : null;
|
return isConnected() ? mIC.getTextAfterCursor(n, flags) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteSurroundingText(final int beforeLength, final int afterLength) {
|
public void deleteTextBeforeCursor(final int beforeLength) {
|
||||||
if (DEBUG_BATCH_NESTING) checkBatchEdit();
|
if (DEBUG_BATCH_NESTING) checkBatchEdit();
|
||||||
// TODO: the following is incorrect if the cursor is not immediately after the composition.
|
// TODO: the following is incorrect if the cursor is not immediately after the composition.
|
||||||
// Right now we never come here in this case because we reset the composing state before we
|
// Right now we never come here in this case because we reset the composing state before we
|
||||||
|
@ -411,7 +406,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
mExpectedSelStart = 0;
|
mExpectedSelStart = 0;
|
||||||
}
|
}
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
mIC.deleteSurroundingText(beforeLength, afterLength);
|
mIC.deleteSurroundingText(beforeLength, 0);
|
||||||
}
|
}
|
||||||
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
|
||||||
}
|
}
|
||||||
|
@ -576,9 +571,9 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
if (!isConnected()) {
|
if (!isConnected()) {
|
||||||
return NgramContext.EMPTY_PREV_WORDS_INFO;
|
return NgramContext.EMPTY_PREV_WORDS_INFO;
|
||||||
}
|
}
|
||||||
final CharSequence prev = getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
|
final CharSequence prev = getTextBeforeCursor(NUM_CHARS_TO_GET_BEFORE_CURSOR, 0);
|
||||||
if (DEBUG_PREVIOUS_TEXT && null != prev) {
|
if (DEBUG_PREVIOUS_TEXT && null != prev) {
|
||||||
final int checkLength = LOOKBACK_CHARACTER_NUM - 1;
|
final int checkLength = NUM_CHARS_TO_GET_BEFORE_CURSOR - 1;
|
||||||
final String reference = prev.length() <= checkLength ? prev.toString()
|
final String reference = prev.length() <= checkLength ? prev.toString()
|
||||||
: prev.subSequence(prev.length() - checkLength, prev.length()).toString();
|
: prev.subSequence(prev.length() - checkLength, prev.length()).toString();
|
||||||
// TODO: right now the following works because mComposingText holds the part of the
|
// TODO: right now the following works because mComposingText holds the part of the
|
||||||
|
@ -621,9 +616,9 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
if (!isConnected()) {
|
if (!isConnected()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final CharSequence before = mIC.getTextBeforeCursor(LOOKBACK_CHARACTER_NUM,
|
final CharSequence before = mIC.getTextBeforeCursor(NUM_CHARS_TO_GET_BEFORE_CURSOR,
|
||||||
InputConnection.GET_TEXT_WITH_STYLES);
|
InputConnection.GET_TEXT_WITH_STYLES);
|
||||||
final CharSequence after = mIC.getTextAfterCursor(LOOKBACK_CHARACTER_NUM,
|
final CharSequence after = mIC.getTextAfterCursor(NUM_CHARS_TO_GET_AFTER_CURSOR,
|
||||||
InputConnection.GET_TEXT_WITH_STYLES);
|
InputConnection.GET_TEXT_WITH_STYLES);
|
||||||
if (before == null || after == null) {
|
if (before == null || after == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -704,7 +699,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
if (DEBUG_BATCH_NESTING) checkBatchEdit();
|
if (DEBUG_BATCH_NESTING) checkBatchEdit();
|
||||||
final int codePointBeforeCursor = getCodePointBeforeCursor();
|
final int codePointBeforeCursor = getCodePointBeforeCursor();
|
||||||
if (Constants.CODE_SPACE == codePointBeforeCursor) {
|
if (Constants.CODE_SPACE == codePointBeforeCursor) {
|
||||||
deleteSurroundingText(1, 0);
|
deleteTextBeforeCursor(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,7 +725,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
}
|
}
|
||||||
// Double-space results in ". ". A backspace to cancel this should result in a single
|
// Double-space results in ". ". A backspace to cancel this should result in a single
|
||||||
// space in the text field, so we replace ". " with a single space.
|
// space in the text field, so we replace ". " with a single space.
|
||||||
deleteSurroundingText(2, 0);
|
deleteTextBeforeCursor(2);
|
||||||
final String singleSpace = " ";
|
final String singleSpace = " ";
|
||||||
commitText(singleSpace, 1);
|
commitText(singleSpace, 1);
|
||||||
return true;
|
return true;
|
||||||
|
@ -752,7 +747,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
+ "find a space just before the cursor.");
|
+ "find a space just before the cursor.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
deleteSurroundingText(2, 0);
|
deleteTextBeforeCursor(2);
|
||||||
final String text = " " + textBeforeCursor.subSequence(0, 1);
|
final String text = " " + textBeforeCursor.subSequence(0, 1);
|
||||||
commitText(text, 1);
|
commitText(text, 1);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1053,7 +1053,7 @@ public final class InputLogic {
|
||||||
// Cancel multi-character input: remove the text we just entered.
|
// Cancel multi-character input: remove the text we just entered.
|
||||||
// This is triggered on backspace after a key that inputs multiple characters,
|
// This is triggered on backspace after a key that inputs multiple characters,
|
||||||
// like the smiley key or the .com key.
|
// like the smiley key or the .com key.
|
||||||
mConnection.deleteSurroundingText(mEnteredText.length(), 0);
|
mConnection.deleteTextBeforeCursor(mEnteredText.length());
|
||||||
StatsUtils.onDeleteMultiCharInput(mEnteredText.length());
|
StatsUtils.onDeleteMultiCharInput(mEnteredText.length());
|
||||||
mEnteredText = null;
|
mEnteredText = null;
|
||||||
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
|
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
|
||||||
|
@ -1098,7 +1098,7 @@ public final class InputLogic {
|
||||||
- mConnection.getExpectedSelectionStart();
|
- mConnection.getExpectedSelectionStart();
|
||||||
mConnection.setSelection(mConnection.getExpectedSelectionEnd(),
|
mConnection.setSelection(mConnection.getExpectedSelectionEnd(),
|
||||||
mConnection.getExpectedSelectionEnd());
|
mConnection.getExpectedSelectionEnd());
|
||||||
mConnection.deleteSurroundingText(numCharsDeleted, 0);
|
mConnection.deleteTextBeforeCursor(numCharsDeleted);
|
||||||
StatsUtils.onBackspaceSelectedText(numCharsDeleted);
|
StatsUtils.onBackspaceSelectedText(numCharsDeleted);
|
||||||
} else {
|
} else {
|
||||||
// There is no selection, just delete one character.
|
// There is no selection, just delete one character.
|
||||||
|
@ -1138,13 +1138,13 @@ public final class InputLogic {
|
||||||
// broken apps expect something to happen in this case so that they can
|
// broken apps expect something to happen in this case so that they can
|
||||||
// catch it and have their broken interface react. If you need the keyboard
|
// catch it and have their broken interface react. If you need the keyboard
|
||||||
// to do this, you're doing it wrong -- please fix your app.
|
// to do this, you're doing it wrong -- please fix your app.
|
||||||
mConnection.deleteSurroundingText(1, 0);
|
mConnection.deleteTextBeforeCursor(1);
|
||||||
// TODO: Add a new StatsUtils method onBackspaceWhenNoText()
|
// TODO: Add a new StatsUtils method onBackspaceWhenNoText()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int lengthToDelete =
|
final int lengthToDelete =
|
||||||
Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
|
Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
|
||||||
mConnection.deleteSurroundingText(lengthToDelete, 0);
|
mConnection.deleteTextBeforeCursor(lengthToDelete);
|
||||||
int totalDeletedLength = lengthToDelete;
|
int totalDeletedLength = lengthToDelete;
|
||||||
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
|
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
|
||||||
// If this is an accelerated (i.e., double) deletion, then we need to
|
// If this is an accelerated (i.e., double) deletion, then we need to
|
||||||
|
@ -1157,7 +1157,7 @@ public final class InputLogic {
|
||||||
if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
|
if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
|
||||||
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
||||||
codePointBeforeCursorToDeleteAgain) ? 2 : 1;
|
codePointBeforeCursorToDeleteAgain) ? 2 : 1;
|
||||||
mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
|
mConnection.deleteTextBeforeCursor(lengthToDeleteAgain);
|
||||||
totalDeletedLength += lengthToDeleteAgain;
|
totalDeletedLength += lengthToDeleteAgain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1241,7 +1241,7 @@ public final class InputLogic {
|
||||||
if (Constants.CODE_SPACE != codePointBeforeCursor) {
|
if (Constants.CODE_SPACE != codePointBeforeCursor) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mConnection.deleteSurroundingText(1, 0);
|
mConnection.deleteTextBeforeCursor(1);
|
||||||
final String text = event.getTextToCommit() + " ";
|
final String text = event.getTextToCommit() + " ";
|
||||||
mConnection.commitText(text, 1);
|
mConnection.commitText(text, 1);
|
||||||
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
|
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
|
||||||
|
@ -1331,7 +1331,7 @@ public final class InputLogic {
|
||||||
Character.codePointAt(lastTwo, length - 3) : lastTwo.charAt(length - 2);
|
Character.codePointAt(lastTwo, length - 3) : lastTwo.charAt(length - 2);
|
||||||
if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) {
|
if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) {
|
||||||
cancelDoubleSpacePeriodCountdown();
|
cancelDoubleSpacePeriodCountdown();
|
||||||
mConnection.deleteSurroundingText(1, 0);
|
mConnection.deleteTextBeforeCursor(1);
|
||||||
final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
|
final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
|
||||||
.mSentenceSeparatorAndSpace;
|
.mSentenceSeparatorAndSpace;
|
||||||
mConnection.commitText(textToInsert, 1);
|
mConnection.commitText(textToInsert, 1);
|
||||||
|
@ -1399,7 +1399,7 @@ public final class InputLogic {
|
||||||
mConnection.finishComposingText();
|
mConnection.finishComposingText();
|
||||||
mRecapitalizeStatus.rotate();
|
mRecapitalizeStatus.rotate();
|
||||||
mConnection.setSelection(selectionEnd, selectionEnd);
|
mConnection.setSelection(selectionEnd, selectionEnd);
|
||||||
mConnection.deleteSurroundingText(numCharsSelected, 0);
|
mConnection.deleteTextBeforeCursor(numCharsSelected);
|
||||||
mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0);
|
mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0);
|
||||||
mConnection.setSelection(mRecapitalizeStatus.getNewCursorStart(),
|
mConnection.setSelection(mRecapitalizeStatus.getNewCursorStart(),
|
||||||
mRecapitalizeStatus.getNewCursorEnd());
|
mRecapitalizeStatus.getNewCursorEnd());
|
||||||
|
@ -1637,7 +1637,7 @@ public final class InputLogic {
|
||||||
+ "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
|
+ "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mConnection.deleteSurroundingText(deleteLength, 0);
|
mConnection.deleteTextBeforeCursor(deleteLength);
|
||||||
if (!TextUtils.isEmpty(committedWord)) {
|
if (!TextUtils.isEmpty(committedWord)) {
|
||||||
unlearnWord(committedWordString, inputTransaction.mSettingsValues,
|
unlearnWord(committedWordString, inputTransaction.mSettingsValues,
|
||||||
Constants.EVENT_REVERT);
|
Constants.EVENT_REVERT);
|
||||||
|
|
Loading…
Reference in New Issue