From 0fd625bcfdfac1c10e7bd7f9088bf425fec08989 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 20 Dec 2011 17:52:29 +0900 Subject: [PATCH] Fix a bug with wrong auto-correct cancellation Auto-correct cancellation would sometimes kick in at wrong times, causing crashes. Bug: 5784542 Change-Id: I68dd6b8d9237ce9b66af2dc63e77ba6dd5fd69dd --- .../android/inputmethod/latin/LatinIME.java | 16 ++++--- .../inputmethod/latin/WordComposer.java | 44 ++++++++++++++++--- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 60f8ce8d8..d2b1e9bca 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1071,7 +1071,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void commitTyped(final InputConnection ic) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mWordComposer.onCommitWord(); + mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { if (ic != null) { ic.commitText(typedWord, 1); @@ -1802,7 +1802,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitBestWord(autoCorrection); + commitChosenWord(autoCorrection, WordComposer.COMMIT_TYPE_DECIDED_WORD); // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -1868,7 +1868,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } mExpectingUpdateSelection = true; - commitBestWord(suggestion); + commitChosenWord(suggestion, WordComposer.COMMIT_TYPE_MANUAL_PICK); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -1927,7 +1927,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * Commits the chosen word to the text field and saves it for later retrieval. */ - private void commitBestWord(CharSequence bestWord) { + private void commitChosenWord(final CharSequence bestWord, final int commitType) { final KeyboardSwitcher switcher = mKeyboardSwitcher; if (!switcher.isKeyboardAvailable()) return; @@ -1942,7 +1942,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(bestWord, 1); } } - mWordComposer.onCommitWord(); + // TODO: figure out here if this is an auto-correct or if the best word is actually + // what user typed. Note: currently this is done much later in + // WordComposer#didAutoCorrectToAnotherWord by string equality of the remembered + // strings. + mWordComposer.onCommitWord(commitType); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2118,7 +2122,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Re-insert the separator ic.commitText(separator, 1); mWordComposer.deleteAutoCorrection(); - mWordComposer.onCommitWord(); + mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_CANCEL_AUTO_CORRECT); Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 54d908011..7e844e9f4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2008 The Android Open Source Project - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -33,6 +33,23 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; + // TODO: Straighten out commit behavior so that the flags here are more understandable, + // and possibly adjust their names. + // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with + // no hinting from the IME. It happens when some external event happens (rotating the device, + // for example) or when auto-correction is off by settings or editor attributes. + public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; + // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. + public static final int COMMIT_TYPE_MANUAL_PICK = 1; + // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best + // for the current user input. It may be different from what the user typed (true auto-correct) + // or it may be exactly what the user typed if it's in the dictionary or the IME does not have + // enough confidence in any suggestion to auto-correct (auto-correct to typed word). + public static final int COMMIT_TYPE_DECIDED_WORD = 2; + // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling + // an auto-correction. + public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + // Storage for all the info about the current input. private static class CharacterStore { /** @@ -291,7 +308,7 @@ public class WordComposer { return mCapsCount > 1; } - /** + /** * Saves the reason why the word is capitalized - whether it was automatic or * due to the user hitting shift in the middle of a sentence. * @param auto whether it was an automatic capitalization due to start of sentence @@ -329,10 +346,23 @@ public class WordComposer { return mCurrentWord.mAutoCorrection; } - // TODO: pass the information about what was committed and how. Was it an auto-correction? - // Was it a completion? Was is what the user typed? - public void onCommitWord() { + // `type' should be one of the COMMIT_TYPE_* constants above. + public void onCommitWord(final int type) { mCommittedWordSavedForSuggestionResuming = mCurrentWord; + // Note: currently, we come here whenever we commit a word. If it's any *other* kind that + // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. + // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user + // typed because the IME decided *not* to auto-correct for whatever reason. + // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. + // As it happens these two cases should behave differently, because the former can be + // canceled while the latter can't. Currently, we figure this out in + // #didAutoCorrectToAnotherWord with #equals(). It would be marginally cleaner to do it + // here, but it would be slower (since we would #equals() for each commit, instead of + // only on cancel), and ultimately we want to figure it out even earlier anyway. + if (type != COMMIT_TYPE_DECIDED_WORD) { + // Only ever revert an auto-correct. + mCommittedWordSavedForSuggestionResuming.mAutoCorrection = null; + } // TODO: improve performance by swapping buffers instead of creating a new object. mCurrentWord = new CharacterStore(); }