diff options
Diffstat (limited to 'java')
-rw-r--r-- | java/Android.mk | 14 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/LatinIME.java | 143 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/UserBigramDictionary.java | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/UserUnigramDictionary.java | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/WordComposer.java | 31 |
5 files changed, 128 insertions, 64 deletions
diff --git a/java/Android.mk b/java/Android.mk index 43168e563..36ff506bf 100644 --- a/java/Android.mk +++ b/java/Android.mk @@ -1,3 +1,17 @@ +# Copyright (C) 2011 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 License for the specific language governing permissions and +# limitations under the License. + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a67e4c938..34699a47b 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -203,7 +203,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private boolean mApplicationSpecifiedCompletionOn; private WordComposer mWordComposer = new WordComposer(); - private CharSequence mBestWord; private boolean mHasUncommittedTypedChars; private int mCorrectionMode; @@ -1019,7 +1018,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar .setHasMinimalSuggestion(false); // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); - mBestWord = null; + mWordComposer.deleteAutoCorrection(); setSuggestionStripShown(true); } } @@ -1415,12 +1414,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final int length = mWordComposer.size(); if (length > 0) { mWordComposer.deleteLast(); - final CharSequence textWithUnderline = - mComposingStateManager.isAutoCorrectionIndicatorOn() - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mWordComposer.getTypedWord()) - : mWordComposer.getTypedWord(); - ic.setComposingText(textWithUnderline, 1); + ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); if (mWordComposer.size() == 0) { mHasUncommittedTypedChars = false; // Remaining size equals zero means we just erased the last character of the @@ -1501,21 +1495,31 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x, final int y, final int spaceState) { mVoiceProxy.handleCharacter(); - final InputConnection ic = getCurrentInputConnection(); - if (ic != null) ic.beginBatchEdit(); + if (null != ic) ic.beginBatchEdit(); + // TODO: if ic is null, does it make any sense to call this? + handleCharacterWhileInBatchEdit(primaryCode, keyCodes, x, y, spaceState, ic); + if (null != ic) ic.endBatchEdit(); + } + + // "ic" may be null without this crashing, but the behavior will be really strange + private void handleCharacterWhileInBatchEdit(final int primaryCode, final int[] keyCodes, + final int x, final int y, final int spaceState, final InputConnection ic) { if (SPACE_STATE_MAGIC == spaceState && mSettingsValues.isMagicSpaceStripper(primaryCode)) { - removeTrailingSpaceWhileInBatchEdit(ic); + if (null != ic) removeTrailingSpaceWhileInBatchEdit(ic); } + boolean isComposingWord = mHasUncommittedTypedChars; int code = primaryCode; if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code)) && isSuggestionsRequested() && !isCursorTouchingWord()) { - if (!mHasUncommittedTypedChars) { + if (!isComposingWord) { // Reset entirely the composing state anyway, then start composing a new word unless - // the character is a single quote. - mHasUncommittedTypedChars = (Keyboard.CODE_SINGLE_QUOTE != code); + // the character is a single quote. The idea here is, single quote is not a + // separator and it should be treated as a normal character, except in the first + // position where it should not start composing a word. + isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != code); mWordComposer.reset(); clearSuggestions(); mComposingStateManager.onFinishComposingText(); @@ -1525,7 +1529,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (switcher.isShiftedOrShiftLocked()) { if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT || keyCodes[0] > Character.MAX_CODE_POINT) { - if (null != ic) ic.endBatchEdit(); return; } code = keyCodes[0]; @@ -1539,12 +1542,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { // Some keys, such as [eszett], have upper case as multi-characters. onTextInput(upperCaseString); - if (null != ic) ic.endBatchEdit(); return; } } } - if (mHasUncommittedTypedChars) { + if (isComposingWord) { + mHasUncommittedTypedChars = true; mWordComposer.add(code, keyCodes, x, y); if (ic != null) { // If it's the first letter, make note of auto-caps state @@ -1552,12 +1555,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mWordComposer.setAutoCapitalized(getCurrentAutoCapsState()); mComposingStateManager.onStartComposingText(); } - final CharSequence textWithUnderline = - mComposingStateManager.isAutoCorrectionIndicatorOn() - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mWordComposer.getTypedWord()) - : mWordComposer.getTypedWord(); - ic.setComposingText(textWithUnderline, 1); + ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); } mHandler.postUpdateSuggestions(); } else { @@ -1574,7 +1572,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { Utils.Stats.onNonSeparator((char)code, x, y); } - if (null != ic) ic.endBatchEdit(); } private void handleSeparator(final int primaryCode, final int x, final int y, @@ -1611,6 +1608,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } + if (pickedDefault) { + final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); + final String typedWord = mWordComposer.getTypedWord(); + if (TextUtils.isEmpty(typedWord)) { + throw new RuntimeException("We have non-committed chars but the typed word " + + "is empty? Impossible! I must commit suicide."); + } + if (!typedWord.equals(autoCorrection)) { + // This will make the correction flash for a short while as a visual clue + // to the user that auto-correction happened. + InputConnectionCompatUtils.commitCorrection( + ic, mLastSelectionEnd - typedWord.length(), typedWord, autoCorrection); + } + } + final boolean swapMagicSpace; if (Keyboard.CODE_ENTER == primaryCode && (SPACE_STATE_MAGIC == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)) { @@ -1658,19 +1670,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar Utils.Stats.onSeparator((char)primaryCode, x, y); - if (pickedDefault) { - CharSequence typedWord = mWordComposer.getTypedWord(); - if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) { - InputConnectionCompatUtils.commitCorrection( - ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); - } - } mKeyboardSwitcher.updateShiftState(); if (ic != null) { ic.endBatchEdit(); } } + private CharSequence getTextWithUnderline(final CharSequence text) { + return mComposingStateManager.isAutoCorrectionIndicatorOn() + ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) + : mWordComposer.getTypedWord(); + } + private void handleClose() { commitTyped(getCurrentInputConnection()); mVoiceProxy.handleClose(); @@ -1744,18 +1755,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mComposingStateManager.isAutoCorrectionIndicatorOn(); final boolean newAutoCorrectionIndicator = Utils.willAutoCorrect(words); if (oldAutoCorrectionIndicator != newAutoCorrectionIndicator) { - if (LatinImeLogger.sDBG) { + mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator); + if (DEBUG) { Log.d(TAG, "Flip the indicator. " + oldAutoCorrectionIndicator + " -> " + newAutoCorrectionIndicator); + if (newAutoCorrectionIndicator + != mComposingStateManager.isAutoCorrectionIndicatorOn()) { + throw new RuntimeException("Couldn't flip the indicator! We are not " + + "composing a word right now."); + } } - final CharSequence textWithUnderline = newAutoCorrectionIndicator - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mWordComposer.getTypedWord()) - : mWordComposer.getTypedWord(); + final CharSequence textWithUnderline = + getTextWithUnderline(mWordComposer.getTypedWord()); if (!TextUtils.isEmpty(textWithUnderline)) { ic.setComposingText(textWithUnderline, 1); } - mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator); } } } @@ -1775,7 +1789,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - final WordComposer wordComposer = mWordComposer; // TODO: May need a better way of retrieving previous word final InputConnection ic = getCurrentInputConnection(); final CharSequence prevWord; @@ -1785,18 +1798,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); } // getSuggestedWordBuilder handles gracefully a null value of prevWord - final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(wordComposer, + final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(mWordComposer, prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode); boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); - final CharSequence typedWord = wordComposer.getTypedWord(); + final CharSequence typedWord = mWordComposer.getTypedWord(); // Here, we want to promote a whitelisted word if exists. // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" // but still autocorrected from - in the case the whitelist only capitalizes the word. // The whitelist should be case-insensitive, so it's not possible to be consistent with // a boolean flag. Right now this is handled with a slight hack in // WhitelistDictionary#shouldForciblyAutoCorrectFrom. - final int quotesCount = wordComposer.trailingSingleQuotesCount(); + final int quotesCount = mWordComposer.trailingSingleQuotesCount(); final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected( mSuggest.getUnigramDictionaries(), // If the typed string ends with a single quote, for dictionary lookup purposes @@ -1812,7 +1825,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar autoCorrectionAvailable |= (!allowsToBeAutoCorrected); } // Don't auto-correct words with multiple capital letter - autoCorrectionAvailable &= !wordComposer.isMostlyCaps(); + autoCorrectionAvailable &= !mWordComposer.isMostlyCaps(); // Basically, we update the suggestion strip only when suggestion count > 1. However, // there is an exception: We update the suggestion strip whenever typed word's length @@ -1848,14 +1861,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { if (shouldBlockAutoCorrectionBySafetyNet) { - mBestWord = typedWord; + mWordComposer.setAutoCorrection(typedWord); } else if (suggestedWords.hasAutoCorrectionWord()) { - mBestWord = suggestedWords.getWord(1); + mWordComposer.setAutoCorrection(suggestedWords.getWord(1)); } else { - mBestWord = typedWord; + mWordComposer.setAutoCorrection(typedWord); } } else { - mBestWord = null; + // TODO: replace with mWordComposer.deleteAutoCorrection()? + mWordComposer.setAutoCorrection(null); } setSuggestionStripShown(isSuggestionsStripVisible()); } @@ -1866,16 +1880,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.cancelUpdateSuggestions(); updateSuggestions(); } - if (mBestWord != null && mBestWord.length() > 0) { - Utils.Stats.onAutoCorrection(mWordComposer.getTypedWord(), mBestWord.toString(), - separatorCode); + final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); + if (autoCorrection != null) { + final String typedWord = mWordComposer.getTypedWord(); + Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCode); mExpectingUpdateSelection = true; - commitBestWord(mBestWord); - if (!mBestWord.equals(mWordComposer.getTypedWord())) { - mWordSavedForAutoCorrectCancellation = mBestWord.toString(); + commitBestWord(autoCorrection); + if (!autoCorrection.equals(typedWord)) { + mWordSavedForAutoCorrectCancellation = autoCorrection.toString(); } // Add the word to the user unigram dictionary if it's not a known word - addToUserUnigramAndBigramDictionaries(mBestWord, + addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); return true; } @@ -1947,6 +1962,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } + // TODO: the following is fishy, because if !mHasUncommittedTypedChars we are + // going to log an empty string LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); // Follow it with a space @@ -2154,8 +2171,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, final CharSequence word) { mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard()); - // mBestWord will be set appropriately by updateSuggestions() called by the handler - mBestWord = null; mHasUncommittedTypedChars = true; mComposingStateManager.onStartComposingText(); ic.deleteSurroundingText(word.length(), 0); @@ -2226,8 +2241,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); - if (!". ".equals(textBeforeCursor)) - return false; + if (!". ".equals(textBeforeCursor)) { + // We should not have come here if we aren't just after a ". ". + throw new RuntimeException("Tried to revert double-space combo but we didn't find " + + "\". \" just before the cursor."); + } ic.beginBatchEdit(); ic.deleteSurroundingText(2, 0); ic.commitText(" ", 1); @@ -2241,8 +2259,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to // enter surrogate pairs this code will have been removed. - if (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1)) - return false; + if (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1)) { + // We should not have come here if the text before the cursor is not a space. + throw new RuntimeException("Tried to revert a swap of punctiation but we didn't " + + "find a space just before the cursor."); + } ic.beginBatchEdit(); ic.deleteSurroundingText(2, 0); ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1); @@ -2383,8 +2404,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - public WordComposer getCurrentWord() { - return mWordComposer; + public boolean isAutoCapitalized() { + return mWordComposer.isAutoCapitalized(); } boolean isSoundOn() { diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index 3a1af9311..f80534cb5 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -159,7 +159,7 @@ public class UserBigramDictionary extends ExpandableDictionary { */ public int addBigrams(String word1, String word2) { // remove caps if second word is autocapitalized - if (mIme != null && mIme.getCurrentWord().isAutoCapitalized()) { + if (mIme != null && mIme.isAutoCapitalized()) { word2 = Character.toLowerCase(word2.charAt(0)) + word2.substring(1); } // Do not insert a word as a bigram of itself diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java index de7cb5716..6af20c754 100644 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -149,7 +149,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { final int length = word.length(); // Don't add very short or very long words. if (length < 2 || length > getMaxWordLength()) return; - if (mIme.getCurrentWord().isAutoCapitalized()) { + if (mIme.isAutoCapitalized()) { // Remove caps before adding word = Character.toLowerCase(word.charAt(0)) + word.substring(1); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index dfb00c8ab..8bbcff758 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -41,6 +41,8 @@ public class WordComposer { private int[] mYCoordinates; private StringBuilder mTypedWord; + // An auto-correction for this word out of the dictionary. + private CharSequence mAutoCorrection; private int mCapsCount; @@ -60,6 +62,7 @@ public class WordComposer { mXCoordinates = new int[N]; mYCoordinates = new int[N]; mTrailingSingleQuotesCount = 0; + mAutoCorrection = null; } public WordComposer(WordComposer source) { @@ -75,6 +78,7 @@ public class WordComposer { mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; + mAutoCorrection = null; } /** @@ -86,6 +90,7 @@ public class WordComposer { mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; + mAutoCorrection = null; } /** @@ -140,6 +145,7 @@ public class WordComposer { } else { mTrailingSingleQuotesCount = 0; } + mAutoCorrection = null; } /** @@ -173,6 +179,7 @@ public class WordComposer { int codePoint = word.charAt(i); addKeyInfo(codePoint, keyboard, keyDetector); } + mAutoCorrection = null; } /** @@ -224,11 +231,12 @@ public class WordComposer { ++mTrailingSingleQuotesCount; } } + mAutoCorrection = null; } /** * Returns the word as it was typed, without any correction applied. - * @return the word that was typed so far + * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { return mTypedWord.toString(); @@ -277,4 +285,25 @@ public class WordComposer { public boolean isAutoCapitalized() { return mAutoCapitalized; } + + /** + * Sets the auto-correction for this word. + */ + public void setAutoCorrection(final CharSequence correction) { + mAutoCorrection = correction; + } + + /** + * Remove any auto-correction that may have been set. + */ + public void deleteAutoCorrection() { + mAutoCorrection = null; + } + + /** + * @return the auto-correction for this word, or null if none. + */ + public CharSequence getAutoCorrectionOrNull() { + return mAutoCorrection; + } } |