am 4fa01ee5: Merge "Allow Latin IME to cancel smiley-auto-correct consistenly" into jb-mr1-dev

* commit '4fa01ee570cf4d4aab3a7cdca5246d8f119ac6f1':
  Allow Latin IME to cancel smiley-auto-correct consistenly
This commit is contained in:
Jean Chalard 2012-08-29 01:19:58 -07:00 committed by Android Git Automerger
commit dad8917eee
4 changed files with 61 additions and 44 deletions

View file

@ -38,12 +38,12 @@ public class LastComposedWord {
// an auto-correction. // an auto-correction.
public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3;
public static final int NOT_A_SEPARATOR = -1; public static final String NOT_A_SEPARATOR = "";
public final int[] mPrimaryKeyCodes; public final int[] mPrimaryKeyCodes;
public final String mTypedWord; public final String mTypedWord;
public final String mCommittedWord; public final String mCommittedWord;
public final int mSeparatorCode; public final String mSeparatorString;
public final CharSequence mPrevWord; public final CharSequence mPrevWord;
public final InputPointers mInputPointers = new InputPointers(BinaryDictionary.MAX_WORD_LENGTH); public final InputPointers mInputPointers = new InputPointers(BinaryDictionary.MAX_WORD_LENGTH);
@ -56,14 +56,14 @@ public class LastComposedWord {
// immutable. Do not fiddle with their contents after you passed them to this constructor. // immutable. Do not fiddle with their contents after you passed them to this constructor.
public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers, public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers,
final String typedWord, final String committedWord, final String typedWord, final String committedWord,
final int separatorCode, final CharSequence prevWord) { final String separatorString, final CharSequence prevWord) {
mPrimaryKeyCodes = primaryKeyCodes; mPrimaryKeyCodes = primaryKeyCodes;
if (inputPointers != null) { if (inputPointers != null) {
mInputPointers.copy(inputPointers); mInputPointers.copy(inputPointers);
} }
mTypedWord = typedWord; mTypedWord = typedWord;
mCommittedWord = committedWord; mCommittedWord = committedWord;
mSeparatorCode = separatorCode; mSeparatorString = separatorString;
mActive = true; mActive = true;
mPrevWord = prevWord; mPrevWord = prevWord;
} }
@ -80,7 +80,7 @@ public class LastComposedWord {
return TextUtils.equals(mTypedWord, mCommittedWord); return TextUtils.equals(mTypedWord, mCommittedWord);
} }
public static int getSeparatorLength(final int separatorCode) { public static int getSeparatorLength(final String separatorString) {
return NOT_A_SEPARATOR == separatorCode ? 0 : 1; return StringUtils.codePointCount(separatorString);
} }
} }

View file

@ -1055,7 +1055,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
} }
private void commitTyped(final int separatorCode) { private void commitTyped(final String separatorString) {
if (!mWordComposer.isComposingWord()) return; if (!mWordComposer.isComposingWord()) return;
final CharSequence typedWord = mWordComposer.getTypedWord(); final CharSequence typedWord = mWordComposer.getTypedWord();
if (typedWord.length() > 0) { if (typedWord.length() > 0) {
@ -1063,7 +1063,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final CharSequence prevWord = addToUserHistoryDictionary(typedWord); final CharSequence prevWord = addToUserHistoryDictionary(typedWord);
mLastComposedWord = mWordComposer.commitWord( mLastComposedWord = mWordComposer.commitWord(
LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(),
separatorCode, prevWord); separatorString, prevWord);
} }
} }
@ -1340,7 +1340,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!didAutoCorrect && primaryCode != Keyboard.CODE_SHIFT if (!didAutoCorrect && primaryCode != Keyboard.CODE_SHIFT
&& primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL) && primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL)
mLastComposedWord.deactivate(); mLastComposedWord.deactivate();
mEnteredText = null; if (Keyboard.CODE_DELETE != primaryCode) {
mEnteredText = null;
}
mConnection.endBatchEdit(); mConnection.endBatchEdit();
if (ProductionFlag.IS_EXPERIMENTAL) { if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
@ -1352,7 +1354,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onTextInput(CharSequence rawText) { public void onTextInput(CharSequence rawText) {
mConnection.beginBatchEdit(); mConnection.beginBatchEdit();
if (mWordComposer.isComposingWord()) { if (mWordComposer.isComposingWord()) {
commitCurrentAutoCorrection(LastComposedWord.NOT_A_SEPARATOR); commitCurrentAutoCorrection(rawText.toString());
} else {
resetComposingState(true /* alsoResetLastComposedWord */);
} }
mHandler.postUpdateSuggestionStrip(); mHandler.postUpdateSuggestionStrip();
final CharSequence text = specificTldProcessingOnTextInput(rawText); final CharSequence text = specificTldProcessingOnTextInput(rawText);
@ -1365,7 +1369,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT);
mSpaceState = SPACE_STATE_NONE; mSpaceState = SPACE_STATE_NONE;
mEnteredText = text; mEnteredText = text;
resetComposingState(true /* alsoResetLastComposedWord */);
} }
@Override @Override
@ -1451,18 +1454,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// In many cases, we may have to put the keyboard in auto-shift state again. // In many cases, we may have to put the keyboard in auto-shift state again.
mHandler.postUpdateShiftState(); mHandler.postUpdateShiftState();
if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
// Cancel multi-character input: remove the text we just entered.
// This is triggered on backspace after a key that inputs multiple characters,
// like the smiley key or the .com key.
final int length = mEnteredText.length();
mConnection.deleteSurroundingText(length, 0);
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
// In addition we know that spaceState is false, and that we should not be
// reverting any autocorrect at this point. So we can safely return.
return;
}
if (mWordComposer.isComposingWord()) { if (mWordComposer.isComposingWord()) {
final int length = mWordComposer.size(); final int length = mWordComposer.size();
if (length > 0) { if (length > 0) {
@ -1483,6 +1474,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
revertCommit(); revertCommit();
return; return;
} }
if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
// Cancel multi-character input: remove the text we just entered.
// This is triggered on backspace after a key that inputs multiple characters,
// like the smiley key or the .com key.
final int length = mEnteredText.length();
mConnection.deleteSurroundingText(length, 0);
mEnteredText = null;
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
// In addition we know that spaceState is false, and that we should not be
// reverting any autocorrect at this point. So we can safely return.
return;
}
if (SPACE_STATE_DOUBLE == spaceState) { if (SPACE_STATE_DOUBLE == spaceState) {
mHandler.cancelDoubleSpacesTimer(); mHandler.cancelDoubleSpacesTimer();
if (mConnection.revertDoubleSpace()) { if (mConnection.revertDoubleSpace()) {
@ -1626,10 +1629,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Handle separator // Handle separator
if (mWordComposer.isComposingWord()) { if (mWordComposer.isComposingWord()) {
if (mCurrentSettings.mCorrectionEnabled) { if (mCurrentSettings.mCorrectionEnabled) {
commitCurrentAutoCorrection(primaryCode); // TODO: maybe cache Strings in an <String> sparse array or something
commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
didAutoCorrect = true; didAutoCorrect = true;
} else { } else {
commitTyped(primaryCode); commitTyped(new String(new int[]{primaryCode}, 0, 1));
} }
} }
@ -1834,7 +1838,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setSuggestionStripShown(isSuggestionsStripVisible()); setSuggestionStripShown(isSuggestionsStripVisible());
} }
private void commitCurrentAutoCorrection(final int separatorCodePoint) { private void commitCurrentAutoCorrection(final String separatorString) {
// Complete any pending suggestions query first // Complete any pending suggestions query first
if (mHandler.hasPendingUpdateSuggestions()) { if (mHandler.hasPendingUpdateSuggestions()) {
updateSuggestionStrip(); updateSuggestionStrip();
@ -1848,10 +1852,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
throw new RuntimeException("We have an auto-correction but the typed word " throw new RuntimeException("We have an auto-correction but the typed word "
+ "is empty? Impossible! I must commit suicide."); + "is empty? Impossible! I must commit suicide.");
} }
Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorString);
mExpectingUpdateSelection = true; mExpectingUpdateSelection = true;
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
separatorCodePoint); separatorString);
if (!typedWord.equals(autoCorrection)) { if (!typedWord.equals(autoCorrection)) {
// This will make the correction flash for a short while as a visual clue // This will make the correction flash for a short while as a visual clue
// to the user that auto-correction happened. // to the user that auto-correction happened.
@ -1949,7 +1953,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
* Commits the chosen word to the text field and saves it for later retrieval. * Commits the chosen word to the text field and saves it for later retrieval.
*/ */
private void commitChosenWord(final CharSequence chosenWord, final int commitType, private void commitChosenWord(final CharSequence chosenWord, final int commitType,
final int separatorCode) { final String separatorString) {
final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1);
@ -1960,7 +1964,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// LastComposedWord#didCommitTypedWord by string equality of the remembered // LastComposedWord#didCommitTypedWord by string equality of the remembered
// strings. // strings.
mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(),
separatorCode, prevWord); separatorString, prevWord);
} }
private void setPunctuationSuggestions() { private void setPunctuationSuggestions() {
@ -2030,7 +2034,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final CharSequence committedWord = mLastComposedWord.mCommittedWord; final CharSequence committedWord = mLastComposedWord.mCommittedWord;
final int cancelLength = committedWord.length(); final int cancelLength = committedWord.length();
final int separatorLength = LastComposedWord.getSeparatorLength( final int separatorLength = LastComposedWord.getSeparatorLength(
mLastComposedWord.mSeparatorCode); mLastComposedWord.mSeparatorString);
// TODO: should we check our saved separator against the actual contents of the text view? // TODO: should we check our saved separator against the actual contents of the text view?
final int deleteLength = cancelLength + separatorLength; final int deleteLength = cancelLength + separatorLength;
if (DEBUG) { if (DEBUG) {
@ -2051,10 +2055,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mUserHistoryDictionary.cancelAddingUserHistory( mUserHistoryDictionary.cancelAddingUserHistory(
previousWord.toString(), committedWord.toString()); previousWord.toString(), committedWord.toString());
} }
mConnection.commitText(originallyTypedWord, 1); mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
// Re-insert the separator Utils.Stats.onSeparator(mLastComposedWord.mSeparatorString,
sendKeyCodePoint(mLastComposedWord.mSeparatorCode);
Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
if (ProductionFlag.IS_EXPERIMENTAL) { if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_revertCommit(originallyTypedWord); ResearchLogger.latinIME_revertCommit(originallyTypedWord);

View file

@ -29,7 +29,6 @@ import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log; import android.util.Log;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@ -394,23 +393,39 @@ public class Utils {
} }
public static class Stats { public static class Stats {
static final int NOT_A_SEPARATOR_CODE_POINT = -1;
public static void onNonSeparator(final char code, final int x, public static void onNonSeparator(final char code, final int x,
final int y) { final int y) {
RingCharBuffer.getInstance().push(code, x, y); RingCharBuffer.getInstance().push(code, x, y);
LatinImeLogger.logOnInputChar(); LatinImeLogger.logOnInputChar();
} }
public static void onSeparator(final int code, final int x, public static void onSeparator(final int code, final int x, final int y) {
final int y) { // Helper method to log a single code point separator
// TODO: accept code points // TODO: cache this mapping of a code point to a string in a sparse array in StringUtils
RingCharBuffer.getInstance().push((char)code, x, y); onSeparator(new String(new int[]{code}, 0, 1), x, y);
}
public static void onSeparator(final String separator, final int x, final int y) {
final int length = separator.length();
for (int i = 0; i < length; i = Character.offsetByCodePoints(separator, i, 1)) {
int codePoint = Character.codePointAt(separator, i);
// TODO: accept code points
RingCharBuffer.getInstance().push((char)codePoint, x, y);
}
LatinImeLogger.logOnInputSeparator(); LatinImeLogger.logOnInputSeparator();
} }
public static void onAutoCorrection(final String typedWord, final String correctedWord, public static void onAutoCorrection(final String typedWord, final String correctedWord,
final int separatorCode) { final String separatorString) {
if (TextUtils.isEmpty(typedWord)) return; if (TextUtils.isEmpty(typedWord)) return;
LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, separatorCode); // TODO: this fails when the separator is more than 1 code point long, but
// the backend can't handle it yet. The only case when this happens is with
// smileys and other multi-character keys.
final int codePoint = TextUtils.isEmpty(separatorString) ? NOT_A_SEPARATOR_CODE_POINT
: separatorString.codePointAt(0);
LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, codePoint);
} }
public static void onAutoCorrectionCancellation() { public static void onAutoCorrectionCancellation() {

View file

@ -336,14 +336,14 @@ public class WordComposer {
// `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above.
public LastComposedWord commitWord(final int type, final String committedWord, public LastComposedWord commitWord(final int type, final String committedWord,
final int separatorCode, final CharSequence prevWord) { final String separatorString, final CharSequence prevWord) {
// Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK
// or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate
// the last composed word to ensure this does not happen. // the last composed word to ensure this does not happen.
final int[] primaryKeyCodes = mPrimaryKeyCodes; final int[] primaryKeyCodes = mPrimaryKeyCodes;
mPrimaryKeyCodes = new int[N]; mPrimaryKeyCodes = new int[N];
final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes,
mInputPointers, mTypedWord.toString(), committedWord, separatorCode, mInputPointers, mTypedWord.toString(), committedWord, separatorString,
prevWord); prevWord);
mInputPointers.reset(); mInputPointers.reset();
if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD