Loading java/src/com/android/inputmethod/latin/LatinIME.java +12 −159 Original line number Diff line number Diff line Loading @@ -73,7 +73,6 @@ import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; Loading Loading @@ -228,39 +227,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Keeps track of most recently inserted text (multi-character key) for reverting private CharSequence mEnteredText; private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>(); public class WordAlternatives { private final CharSequence mChosenWord; private final WordComposer mWordComposer; public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { mChosenWord = chosenWord; mWordComposer = wordComposer; } public CharSequence getChosenWord() { return mChosenWord; } public CharSequence getOriginalWord() { return mWordComposer.getTypedWord(); } public SuggestedWords.Builder getAlternatives() { return getTypedSuggestions(mWordComposer); } @Override public int hashCode() { return mChosenWord.hashCode(); } @Override public boolean equals(Object o) { return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o); } } public final UIHandler mHandler = new UIHandler(); Loading @@ -283,7 +249,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateSuggestions(); break; case MSG_UPDATE_OLD_SUGGESTIONS: setOldSuggestions(); mRecorrection.setRecorrectionSuggestions(mVoiceProxy, mCandidateView, mSuggest, mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, mLastSelectionStart, mLastSelectionEnd, mWordSeparators); break; case MSG_UPDATE_SHIFT_STATE: switcher.updateShiftState(); Loading Loading @@ -749,7 +717,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // If the composing span has been cleared, save the typed word in the history for // recorrection before we reset the candidate strip. Then, we'll be able to show // suggestions for recorrection right away. saveWordInHistory(mComposing); mRecorrection.saveWordInHistory(mWord, mComposing); } mComposing.setLength(0); mHasUncommittedTypedChars = false; Loading Loading @@ -832,7 +800,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mOptionsDialog = null; } mVoiceProxy.hideVoiceWindow(mConfigurationChanging); mWordHistory.clear(); mRecorrection.clearWordsInHistory(); super.hideWindow(); } Loading Loading @@ -1164,7 +1132,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.commitVoiceInput(); InputConnection ic = getCurrentInputConnection(); if (ic == null) return; abortRecorrection(false); mRecorrection.abortRecorrection(false); ic.beginBatchEdit(); commitTyped(ic); maybeRemovePreviousPeriod(text); Loading Loading @@ -1270,15 +1238,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } public void abortRecorrection(boolean force) { if (force || TextEntryState.isRecorrecting()) { TextEntryState.onAbortRecorrection(); setCandidatesViewShown(isCandidateStripVisible()); getCurrentInputConnection().finishComposingText(); clearSuggestions(); } } private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) { mVoiceProxy.handleCharacter(); Loading @@ -1287,7 +1246,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } if (mLastSelectionStart == mLastSelectionEnd) { abortRecorrection(false); mRecorrection.abortRecorrection(false); } int code = primaryCode; Loading @@ -1295,7 +1254,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mHasUncommittedTypedChars) { mHasUncommittedTypedChars = true; mComposing.setLength(0); saveWordInHistory(mBestWord); mRecorrection.saveWordInHistory(mWord, mBestWord); mWord.reset(); clearSuggestions(); } Loading Loading @@ -1363,7 +1322,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.beginBatchEdit(); abortRecorrection(false); mRecorrection.abortRecorrection(false); } if (mHasUncommittedTypedChars) { // In certain languages where single quote is a separator, it's better Loading Loading @@ -1432,22 +1391,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar inputView.closing(); } private void saveWordInHistory(CharSequence result) { if (mWord.size() <= 1) { return; } // Skip if result is null. It happens in some edge case. if (TextUtils.isEmpty(result)) { return; } // Make a copy of the CharSequence, since it is/could be a mutable CharSequence final String resultCopy = result.toString(); WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(mWord)); mWordHistory.add(entry); } public boolean isSuggestionsRequested() { return mIsSettingsSuggestionStripOn && (mCorrectionMode > 0 || isShowingSuggestionsStrip()); Loading @@ -1463,7 +1406,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar && mOrientation == Configuration.ORIENTATION_PORTRAIT); } private boolean isCandidateStripVisible() { public boolean isCandidateStripVisible() { if (mCandidateView == null) return false; if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting()) Loading Loading @@ -1525,16 +1468,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar showSuggestions(mWord); } private SuggestedWords.Builder getTypedSuggestions(WordComposer word) { return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null); } private void showCorrections(WordAlternatives alternatives) { SuggestedWords.Builder builder = alternatives.getAlternatives(); builder.setTypedWordValid(false).setHasMinimalSuggestion(false); showSuggestions(builder.build(), alternatives.getOriginalWord()); } private void showSuggestions(WordComposer word) { // TODO: May need a better way of retrieving previous word CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(), Loading Loading @@ -1573,7 +1506,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar showSuggestions(builder.build(), typedWord); } private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) { Loading Loading @@ -1728,91 +1661,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.rememberReplacedWord(suggestion, mWordSeparators); ic.commitText(suggestion, 1); } saveWordInHistory(suggestion); mRecorrection.saveWordInHistory(mWord, suggestion); mHasUncommittedTypedChars = false; mCommittedLength = suggestion.length(); } /** * Tries to apply any typed alternatives for the word if we have any cached alternatives, * otherwise tries to find new corrections and completions for the word. * @param touching The word that the cursor is touching, with position information * @return true if an alternative was found, false otherwise. */ private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) { // If we didn't find a match, search for result in typed word history WordComposer foundWord = null; WordAlternatives alternatives = null; // Search old suggestions to suggest re-corrected suggestions. for (WordAlternatives entry : mWordHistory) { if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) { foundWord = entry.mWordComposer; alternatives = entry; break; } } // If we didn't find a match, at least suggest corrections as re-corrected suggestions. if (foundWord == null && (AutoCorrection.isValidWord( mSuggest.getUnigramDictionaries(), touching.mWord, true))) { foundWord = new WordComposer(); for (int i = 0; i < touching.mWord.length(); i++) { foundWord.add(touching.mWord.charAt(i), new int[] { touching.mWord.charAt(i) }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0))); } // Found a match, show suggestions if (foundWord != null || alternatives != null) { if (alternatives == null) { alternatives = new WordAlternatives(touching.mWord, foundWord); } showCorrections(alternatives); if (foundWord != null) { mWord = new WordComposer(foundWord); } else { mWord.reset(); } return true; } return false; } private void setOldSuggestions() { if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; mVoiceProxy.setShowingVoiceSuggestions(false); if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) { return; } InputConnection ic = getCurrentInputConnection(); if (ic == null) return; if (!mHasUncommittedTypedChars) { // Extract the selected or touching text EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic, mLastSelectionStart, mLastSelectionEnd, mWordSeparators); if (touching != null && touching.mWord.length() > 1) { ic.beginBatchEdit(); if (!mVoiceProxy.applyVoiceAlternatives(touching) && !applyTypedAlternatives(touching)) { abortRecorrection(true); } else { TextEntryState.selectedForRecorrection(); InputConnectionCompatUtils.underlineWord(ic, touching); } ic.endBatchEdit(); } else { abortRecorrection(true); setPunctuationSuggestions(); // Show the punctuation suggestions list } } else { abortRecorrection(true); } } private static final WordComposer sEmptyWordComposer = new WordComposer(); private void updateBigramPredictions() { if (mSuggest == null || !isSuggestionsRequested()) Loading java/src/com/android/inputmethod/latin/Recorrection.java +126 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.KeyboardSwitcher; import android.content.SharedPreferences; Loading @@ -25,6 +27,8 @@ import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import java.util.ArrayList; /** * Manager of re-correction functionalities */ Loading @@ -33,6 +37,7 @@ public class Recorrection { private LatinIME mService; private boolean mRecorrectionEnabled = false; private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>(); public static Recorrection getInstance() { return sInstance; Loading Loading @@ -108,7 +113,7 @@ public class Recorrection { mService.mHandler.cancelUpdateBigramPredictions(); mService.mHandler.postUpdateOldSuggestions(); } else { mService.abortRecorrection(false); abortRecorrection(false); // If showing the "touch again to save" hint, do not replace it. Else, // show the bigrams if we are at the end of the text, punctuation otherwise. if (candidateView != null Loading @@ -127,4 +132,124 @@ public class Recorrection { } } } public void saveWordInHistory(WordComposer word, CharSequence result) { if (word.size() <= 1) { return; } // Skip if result is null. It happens in some edge case. if (TextUtils.isEmpty(result)) { return; } // Make a copy of the CharSequence, since it is/could be a mutable CharSequence final String resultCopy = result.toString(); WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(word)); mWordHistory.add(entry); } public void clearWordsInHistory() { mWordHistory.clear(); } /** * Tries to apply any typed alternatives for the word if we have any cached alternatives, * otherwise tries to find new corrections and completions for the word. * @param touching The word that the cursor is touching, with position information * @return true if an alternative was found, false otherwise. */ public boolean applyTypedAlternatives(WordComposer word, Suggest suggest, KeyboardSwitcher keyboardSwitcher, EditingUtils.SelectedWord touching) { // If we didn't find a match, search for result in typed word history WordComposer foundWord = null; WordAlternatives alternatives = null; // Search old suggestions to suggest re-corrected suggestions. for (WordAlternatives entry : mWordHistory) { if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) { foundWord = entry.mWordComposer; alternatives = entry; break; } } // If we didn't find a match, at least suggest corrections as re-corrected suggestions. if (foundWord == null && (AutoCorrection.isValidWord(suggest.getUnigramDictionaries(), touching.mWord, true))) { foundWord = new WordComposer(); for (int i = 0; i < touching.mWord.length(); i++) { foundWord.add(touching.mWord.charAt(i), new int[] { touching.mWord.charAt(i) }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0))); } // Found a match, show suggestions if (foundWord != null || alternatives != null) { if (alternatives == null) { alternatives = new WordAlternatives(touching.mWord, foundWord); } showRecorrections(suggest, keyboardSwitcher, alternatives); if (foundWord != null) { word.init(foundWord); } else { word.reset(); } return true; } return false; } private void showRecorrections(Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordAlternatives alternatives) { SuggestedWords.Builder builder = alternatives.getAlternatives(suggest, keyboardSwitcher); builder.setTypedWordValid(false).setHasMinimalSuggestion(false); mService.showSuggestions(builder.build(), alternatives.getOriginalWord()); } public void setRecorrectionSuggestions(VoiceProxy voiceProxy, CandidateView candidateView, Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word, boolean hasUncommittedTypedChars, int lastSelectionStart, int lastSelectionEnd, String wordSeparators) { if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; voiceProxy.setShowingVoiceSuggestions(false); if (candidateView != null && candidateView.isShowingAddToDictionaryHint()) { return; } InputConnection ic = mService.getCurrentInputConnection(); if (ic == null) return; if (!hasUncommittedTypedChars) { // Extract the selected or touching text EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic, lastSelectionStart, lastSelectionEnd, wordSeparators); if (touching != null && touching.mWord.length() > 1) { ic.beginBatchEdit(); if (applyTypedAlternatives(word, suggest, keyboardSwitcher, touching) || voiceProxy.applyVoiceAlternatives(touching)) { TextEntryState.selectedForRecorrection(); InputConnectionCompatUtils.underlineWord(ic, touching); } else { abortRecorrection(true); } ic.endBatchEdit(); } else { abortRecorrection(true); mService.setPunctuationSuggestions(); // Show the punctuation suggestions list } } else { abortRecorrection(true); } } public void abortRecorrection(boolean force) { if (force || TextEntryState.isRecorrecting()) { TextEntryState.onAbortRecorrection(); mService.setCandidatesViewShown(mService.isCandidateStripVisible()); mService.getCurrentInputConnection().finishComposingText(); mService.clearSuggestions(); } } } java/src/com/android/inputmethod/latin/WordAlternatives.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * 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. */ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.KeyboardSwitcher; import android.text.TextUtils; public class WordAlternatives { public final CharSequence mChosenWord; public final WordComposer mWordComposer; public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { mChosenWord = chosenWord; mWordComposer = wordComposer; } public CharSequence getChosenWord() { return mChosenWord; } public CharSequence getOriginalWord() { return mWordComposer.getTypedWord(); } public SuggestedWords.Builder getAlternatives( Suggest suggest, KeyboardSwitcher keyboardSwitcher) { return getTypedSuggestions(suggest, keyboardSwitcher, mWordComposer); } @Override public int hashCode() { return mChosenWord.hashCode(); } @Override public boolean equals(Object o) { return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o); } private static SuggestedWords.Builder getTypedSuggestions( Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word) { return suggest.getSuggestedWordBuilder(keyboardSwitcher.getInputView(), word, null); } } No newline at end of file java/src/com/android/inputmethod/latin/WordComposer.java +8 −4 Original line number Diff line number Diff line Loading @@ -31,18 +31,18 @@ public class WordComposer { /** * The list of unicode values for each keystroke (including surrounding keys) */ private final ArrayList<int[]> mCodes; private ArrayList<int[]> mCodes; private int mTypedLength; private final int[] mXCoordinates; private final int[] mYCoordinates; private int[] mXCoordinates; private int[] mYCoordinates; /** * The word chosen from the candidate list, until it is committed. */ private String mPreferredWord; private final StringBuilder mTypedWord; private StringBuilder mTypedWord; private int mCapsCount; Loading @@ -63,6 +63,10 @@ public class WordComposer { } WordComposer(WordComposer source) { init(source); } public void init(WordComposer source) { mCodes = new ArrayList<int[]>(source.mCodes); mPreferredWord = source.mPreferredWord; mTypedWord = new StringBuilder(source.mTypedWord); Loading Loading
java/src/com/android/inputmethod/latin/LatinIME.java +12 −159 Original line number Diff line number Diff line Loading @@ -73,7 +73,6 @@ import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; Loading Loading @@ -228,39 +227,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Keeps track of most recently inserted text (multi-character key) for reverting private CharSequence mEnteredText; private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>(); public class WordAlternatives { private final CharSequence mChosenWord; private final WordComposer mWordComposer; public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { mChosenWord = chosenWord; mWordComposer = wordComposer; } public CharSequence getChosenWord() { return mChosenWord; } public CharSequence getOriginalWord() { return mWordComposer.getTypedWord(); } public SuggestedWords.Builder getAlternatives() { return getTypedSuggestions(mWordComposer); } @Override public int hashCode() { return mChosenWord.hashCode(); } @Override public boolean equals(Object o) { return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o); } } public final UIHandler mHandler = new UIHandler(); Loading @@ -283,7 +249,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateSuggestions(); break; case MSG_UPDATE_OLD_SUGGESTIONS: setOldSuggestions(); mRecorrection.setRecorrectionSuggestions(mVoiceProxy, mCandidateView, mSuggest, mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, mLastSelectionStart, mLastSelectionEnd, mWordSeparators); break; case MSG_UPDATE_SHIFT_STATE: switcher.updateShiftState(); Loading Loading @@ -749,7 +717,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // If the composing span has been cleared, save the typed word in the history for // recorrection before we reset the candidate strip. Then, we'll be able to show // suggestions for recorrection right away. saveWordInHistory(mComposing); mRecorrection.saveWordInHistory(mWord, mComposing); } mComposing.setLength(0); mHasUncommittedTypedChars = false; Loading Loading @@ -832,7 +800,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mOptionsDialog = null; } mVoiceProxy.hideVoiceWindow(mConfigurationChanging); mWordHistory.clear(); mRecorrection.clearWordsInHistory(); super.hideWindow(); } Loading Loading @@ -1164,7 +1132,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.commitVoiceInput(); InputConnection ic = getCurrentInputConnection(); if (ic == null) return; abortRecorrection(false); mRecorrection.abortRecorrection(false); ic.beginBatchEdit(); commitTyped(ic); maybeRemovePreviousPeriod(text); Loading Loading @@ -1270,15 +1238,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } public void abortRecorrection(boolean force) { if (force || TextEntryState.isRecorrecting()) { TextEntryState.onAbortRecorrection(); setCandidatesViewShown(isCandidateStripVisible()); getCurrentInputConnection().finishComposingText(); clearSuggestions(); } } private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) { mVoiceProxy.handleCharacter(); Loading @@ -1287,7 +1246,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } if (mLastSelectionStart == mLastSelectionEnd) { abortRecorrection(false); mRecorrection.abortRecorrection(false); } int code = primaryCode; Loading @@ -1295,7 +1254,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mHasUncommittedTypedChars) { mHasUncommittedTypedChars = true; mComposing.setLength(0); saveWordInHistory(mBestWord); mRecorrection.saveWordInHistory(mWord, mBestWord); mWord.reset(); clearSuggestions(); } Loading Loading @@ -1363,7 +1322,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.beginBatchEdit(); abortRecorrection(false); mRecorrection.abortRecorrection(false); } if (mHasUncommittedTypedChars) { // In certain languages where single quote is a separator, it's better Loading Loading @@ -1432,22 +1391,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar inputView.closing(); } private void saveWordInHistory(CharSequence result) { if (mWord.size() <= 1) { return; } // Skip if result is null. It happens in some edge case. if (TextUtils.isEmpty(result)) { return; } // Make a copy of the CharSequence, since it is/could be a mutable CharSequence final String resultCopy = result.toString(); WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(mWord)); mWordHistory.add(entry); } public boolean isSuggestionsRequested() { return mIsSettingsSuggestionStripOn && (mCorrectionMode > 0 || isShowingSuggestionsStrip()); Loading @@ -1463,7 +1406,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar && mOrientation == Configuration.ORIENTATION_PORTRAIT); } private boolean isCandidateStripVisible() { public boolean isCandidateStripVisible() { if (mCandidateView == null) return false; if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting()) Loading Loading @@ -1525,16 +1468,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar showSuggestions(mWord); } private SuggestedWords.Builder getTypedSuggestions(WordComposer word) { return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null); } private void showCorrections(WordAlternatives alternatives) { SuggestedWords.Builder builder = alternatives.getAlternatives(); builder.setTypedWordValid(false).setHasMinimalSuggestion(false); showSuggestions(builder.build(), alternatives.getOriginalWord()); } private void showSuggestions(WordComposer word) { // TODO: May need a better way of retrieving previous word CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(), Loading Loading @@ -1573,7 +1506,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar showSuggestions(builder.build(), typedWord); } private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) { Loading Loading @@ -1728,91 +1661,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.rememberReplacedWord(suggestion, mWordSeparators); ic.commitText(suggestion, 1); } saveWordInHistory(suggestion); mRecorrection.saveWordInHistory(mWord, suggestion); mHasUncommittedTypedChars = false; mCommittedLength = suggestion.length(); } /** * Tries to apply any typed alternatives for the word if we have any cached alternatives, * otherwise tries to find new corrections and completions for the word. * @param touching The word that the cursor is touching, with position information * @return true if an alternative was found, false otherwise. */ private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) { // If we didn't find a match, search for result in typed word history WordComposer foundWord = null; WordAlternatives alternatives = null; // Search old suggestions to suggest re-corrected suggestions. for (WordAlternatives entry : mWordHistory) { if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) { foundWord = entry.mWordComposer; alternatives = entry; break; } } // If we didn't find a match, at least suggest corrections as re-corrected suggestions. if (foundWord == null && (AutoCorrection.isValidWord( mSuggest.getUnigramDictionaries(), touching.mWord, true))) { foundWord = new WordComposer(); for (int i = 0; i < touching.mWord.length(); i++) { foundWord.add(touching.mWord.charAt(i), new int[] { touching.mWord.charAt(i) }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0))); } // Found a match, show suggestions if (foundWord != null || alternatives != null) { if (alternatives == null) { alternatives = new WordAlternatives(touching.mWord, foundWord); } showCorrections(alternatives); if (foundWord != null) { mWord = new WordComposer(foundWord); } else { mWord.reset(); } return true; } return false; } private void setOldSuggestions() { if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; mVoiceProxy.setShowingVoiceSuggestions(false); if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) { return; } InputConnection ic = getCurrentInputConnection(); if (ic == null) return; if (!mHasUncommittedTypedChars) { // Extract the selected or touching text EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic, mLastSelectionStart, mLastSelectionEnd, mWordSeparators); if (touching != null && touching.mWord.length() > 1) { ic.beginBatchEdit(); if (!mVoiceProxy.applyVoiceAlternatives(touching) && !applyTypedAlternatives(touching)) { abortRecorrection(true); } else { TextEntryState.selectedForRecorrection(); InputConnectionCompatUtils.underlineWord(ic, touching); } ic.endBatchEdit(); } else { abortRecorrection(true); setPunctuationSuggestions(); // Show the punctuation suggestions list } } else { abortRecorrection(true); } } private static final WordComposer sEmptyWordComposer = new WordComposer(); private void updateBigramPredictions() { if (mSuggest == null || !isSuggestionsRequested()) Loading
java/src/com/android/inputmethod/latin/Recorrection.java +126 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.KeyboardSwitcher; import android.content.SharedPreferences; Loading @@ -25,6 +27,8 @@ import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import java.util.ArrayList; /** * Manager of re-correction functionalities */ Loading @@ -33,6 +37,7 @@ public class Recorrection { private LatinIME mService; private boolean mRecorrectionEnabled = false; private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>(); public static Recorrection getInstance() { return sInstance; Loading Loading @@ -108,7 +113,7 @@ public class Recorrection { mService.mHandler.cancelUpdateBigramPredictions(); mService.mHandler.postUpdateOldSuggestions(); } else { mService.abortRecorrection(false); abortRecorrection(false); // If showing the "touch again to save" hint, do not replace it. Else, // show the bigrams if we are at the end of the text, punctuation otherwise. if (candidateView != null Loading @@ -127,4 +132,124 @@ public class Recorrection { } } } public void saveWordInHistory(WordComposer word, CharSequence result) { if (word.size() <= 1) { return; } // Skip if result is null. It happens in some edge case. if (TextUtils.isEmpty(result)) { return; } // Make a copy of the CharSequence, since it is/could be a mutable CharSequence final String resultCopy = result.toString(); WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(word)); mWordHistory.add(entry); } public void clearWordsInHistory() { mWordHistory.clear(); } /** * Tries to apply any typed alternatives for the word if we have any cached alternatives, * otherwise tries to find new corrections and completions for the word. * @param touching The word that the cursor is touching, with position information * @return true if an alternative was found, false otherwise. */ public boolean applyTypedAlternatives(WordComposer word, Suggest suggest, KeyboardSwitcher keyboardSwitcher, EditingUtils.SelectedWord touching) { // If we didn't find a match, search for result in typed word history WordComposer foundWord = null; WordAlternatives alternatives = null; // Search old suggestions to suggest re-corrected suggestions. for (WordAlternatives entry : mWordHistory) { if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) { foundWord = entry.mWordComposer; alternatives = entry; break; } } // If we didn't find a match, at least suggest corrections as re-corrected suggestions. if (foundWord == null && (AutoCorrection.isValidWord(suggest.getUnigramDictionaries(), touching.mWord, true))) { foundWord = new WordComposer(); for (int i = 0; i < touching.mWord.length(); i++) { foundWord.add(touching.mWord.charAt(i), new int[] { touching.mWord.charAt(i) }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0))); } // Found a match, show suggestions if (foundWord != null || alternatives != null) { if (alternatives == null) { alternatives = new WordAlternatives(touching.mWord, foundWord); } showRecorrections(suggest, keyboardSwitcher, alternatives); if (foundWord != null) { word.init(foundWord); } else { word.reset(); } return true; } return false; } private void showRecorrections(Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordAlternatives alternatives) { SuggestedWords.Builder builder = alternatives.getAlternatives(suggest, keyboardSwitcher); builder.setTypedWordValid(false).setHasMinimalSuggestion(false); mService.showSuggestions(builder.build(), alternatives.getOriginalWord()); } public void setRecorrectionSuggestions(VoiceProxy voiceProxy, CandidateView candidateView, Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word, boolean hasUncommittedTypedChars, int lastSelectionStart, int lastSelectionEnd, String wordSeparators) { if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; voiceProxy.setShowingVoiceSuggestions(false); if (candidateView != null && candidateView.isShowingAddToDictionaryHint()) { return; } InputConnection ic = mService.getCurrentInputConnection(); if (ic == null) return; if (!hasUncommittedTypedChars) { // Extract the selected or touching text EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic, lastSelectionStart, lastSelectionEnd, wordSeparators); if (touching != null && touching.mWord.length() > 1) { ic.beginBatchEdit(); if (applyTypedAlternatives(word, suggest, keyboardSwitcher, touching) || voiceProxy.applyVoiceAlternatives(touching)) { TextEntryState.selectedForRecorrection(); InputConnectionCompatUtils.underlineWord(ic, touching); } else { abortRecorrection(true); } ic.endBatchEdit(); } else { abortRecorrection(true); mService.setPunctuationSuggestions(); // Show the punctuation suggestions list } } else { abortRecorrection(true); } } public void abortRecorrection(boolean force) { if (force || TextEntryState.isRecorrecting()) { TextEntryState.onAbortRecorrection(); mService.setCandidatesViewShown(mService.isCandidateStripVisible()); mService.getCurrentInputConnection().finishComposingText(); mService.clearSuggestions(); } } }
java/src/com/android/inputmethod/latin/WordAlternatives.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * 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. */ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.KeyboardSwitcher; import android.text.TextUtils; public class WordAlternatives { public final CharSequence mChosenWord; public final WordComposer mWordComposer; public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { mChosenWord = chosenWord; mWordComposer = wordComposer; } public CharSequence getChosenWord() { return mChosenWord; } public CharSequence getOriginalWord() { return mWordComposer.getTypedWord(); } public SuggestedWords.Builder getAlternatives( Suggest suggest, KeyboardSwitcher keyboardSwitcher) { return getTypedSuggestions(suggest, keyboardSwitcher, mWordComposer); } @Override public int hashCode() { return mChosenWord.hashCode(); } @Override public boolean equals(Object o) { return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o); } private static SuggestedWords.Builder getTypedSuggestions( Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word) { return suggest.getSuggestedWordBuilder(keyboardSwitcher.getInputView(), word, null); } } No newline at end of file
java/src/com/android/inputmethod/latin/WordComposer.java +8 −4 Original line number Diff line number Diff line Loading @@ -31,18 +31,18 @@ public class WordComposer { /** * The list of unicode values for each keystroke (including surrounding keys) */ private final ArrayList<int[]> mCodes; private ArrayList<int[]> mCodes; private int mTypedLength; private final int[] mXCoordinates; private final int[] mYCoordinates; private int[] mXCoordinates; private int[] mYCoordinates; /** * The word chosen from the candidate list, until it is committed. */ private String mPreferredWord; private final StringBuilder mTypedWord; private StringBuilder mTypedWord; private int mCapsCount; Loading @@ -63,6 +63,10 @@ public class WordComposer { } WordComposer(WordComposer source) { init(source); } public void init(WordComposer source) { mCodes = new ArrayList<int[]>(source.mCodes); mPreferredWord = source.mPreferredWord; mTypedWord = new StringBuilder(source.mTypedWord); Loading