diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
12 files changed, 118 insertions, 183 deletions
diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 54bc29559..eb8b34ccd 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -16,14 +16,14 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.settings.SettingsValues; - import android.content.Context; import android.media.AudioManager; import android.os.Vibrator; import android.view.HapticFeedbackConstants; import android.view.View; +import com.android.inputmethod.latin.settings.SettingsValues; + /** * This class gathers audio feedback and haptic feedback functions. * @@ -86,40 +86,41 @@ public final class AudioAndHapticFeedbackManager { if (mAudioManager == null) { return; } - if (mSoundOn) { - final int sound; - switch (code) { - case Constants.CODE_DELETE: - sound = AudioManager.FX_KEYPRESS_DELETE; - break; - case Constants.CODE_ENTER: - sound = AudioManager.FX_KEYPRESS_RETURN; - break; - case Constants.CODE_SPACE: - sound = AudioManager.FX_KEYPRESS_SPACEBAR; - break; - default: - sound = AudioManager.FX_KEYPRESS_STANDARD; - break; - } - mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume); + if (!mSoundOn) { + return; + } + final int sound; + switch (code) { + case Constants.CODE_DELETE: + sound = AudioManager.FX_KEYPRESS_DELETE; + break; + case Constants.CODE_ENTER: + sound = AudioManager.FX_KEYPRESS_RETURN; + break; + case Constants.CODE_SPACE: + sound = AudioManager.FX_KEYPRESS_SPACEBAR; + break; + default: + sound = AudioManager.FX_KEYPRESS_STANDARD; + break; } + mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume); } public void performHapticFeedback(final View viewToPerformHapticFeedbackOn) { if (!mSettingsValues.mVibrateOn) { return; } - if (mSettingsValues.mKeypressVibrationDuration < 0) { - // Go ahead with the system default - if (viewToPerformHapticFeedbackOn != null) { - viewToPerformHapticFeedbackOn.performHapticFeedback( - HapticFeedbackConstants.KEYBOARD_TAP, - HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } + if (mSettingsValues.mKeypressVibrationDuration >= 0) { + vibrate(mSettingsValues.mKeypressVibrationDuration); return; } - vibrate(mSettingsValues.mKeypressVibrationDuration); + // Go ahead with the system default + if (viewToPerformHapticFeedbackOn != null) { + viewToPerformHapticFeedbackOn.performHapticFeedback( + HapticFeedbackConstants.KEYBOARD_TAP, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } } public void onSettingsChanged(final SettingsValues settingsValues) { diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index 48b6a4622..bdf39238a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -574,6 +574,12 @@ public class DictionaryFacilitator { final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) { final ExpandableBinaryDictionary personalizationDict = mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION); + if (personalizationDict == null) { + if (callback != null) { + callback.onFinished(); + } + return; + } final ArrayList<LanguageModelParam> languageModelParams = LanguageModelParam.createLanguageModelParamsFrom( personalizationDataChunk.mTokens, @@ -581,8 +587,7 @@ public class DictionaryFacilitator { this /* dictionaryFacilitator */, spacingAndPunctuations, new DistracterFilterCheckingIsInDictionary( mDistracterFilter, personalizationDict)); - if (personalizationDict == null || languageModelParams == null - || languageModelParams.isEmpty()) { + if (languageModelParams == null || languageModelParams.isEmpty()) { if (callback != null) { callback.onFinished(); } diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index e5e00d59a..cf61855b3 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -49,6 +49,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * queries in native code. This binary dictionary is written to internal storage. */ abstract public class ExpandableBinaryDictionary extends Dictionary { + private static final boolean DEBUG = false; /** Used for Log actions from this class */ private static final String TAG = ExpandableBinaryDictionary.class.getSimpleName(); @@ -325,16 +326,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected void addNgramEntryLocked(final PrevWordsInfo prevWordsInfo, final String word, final int frequency, final int timestamp) { if (!mBinaryDictionary.addNgramEntry(prevWordsInfo, word, frequency, timestamp)) { - Log.e(TAG, "Cannot add n-gram entry."); - Log.e(TAG, " PrevWordsInfo: " + prevWordsInfo); - Log.e(TAG, " word: " + word); + if (DEBUG) { + Log.i(TAG, "Cannot add n-gram entry."); + Log.i(TAG, " PrevWordsInfo: " + prevWordsInfo + ", word: " + word); + } } } /** * Dynamically remove the n-gram entry in the dictionary. */ - public void removeNgramDynamically(final PrevWordsInfo prevWordsInfo, final String word1) { + public void removeNgramDynamically(final PrevWordsInfo prevWordsInfo, final String word) { reloadDictionaryIfRequired(); asyncExecuteTaskWithWriteLock(new Runnable() { @Override @@ -343,7 +345,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return; } runGCIfRequiredLocked(true /* mindsBlockByGC */); - mBinaryDictionary.removeNgramEntry(prevWordsInfo, word1); + if (!mBinaryDictionary.removeNgramEntry(prevWordsInfo, word)) { + if (DEBUG) { + Log.i(TAG, "Cannot remove n-gram entry."); + Log.i(TAG, " PrevWordsInfo: " + prevWordsInfo + ", word: " + word); + } + } } }); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 631d6b63a..35966bb71 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1374,34 +1374,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen callback.onGetSuggestedWords(SuggestedWords.EMPTY); return; } - // Get the word on which we should search the bigrams. If we are composing a word, it's - // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we - // should just skip whitespace if any, so 1. final SettingsValues currentSettings = mSettings.getCurrent(); final int[] additionalFeaturesOptions = currentSettings.mAdditionalFeaturesSettingValues; - - if (DEBUG) { - if (mInputLogic.mWordComposer.isComposingWord() - || mInputLogic.mWordComposer.isBatchMode()) { - final PrevWordsInfo prevWordsInfo - = mInputLogic.mWordComposer.getPrevWordsInfoForSuggestion(); - // TODO: this is for checking consistency with older versions. Remove this when - // we are confident this is stable. - // We're checking the previous word in the text field against the memorized previous - // word. If we are composing a word we should have the second word before the cursor - // memorized, otherwise we should have the first. - final PrevWordsInfo rereadPrevWordsInfo = - mInputLogic.getPrevWordsInfoFromNthPreviousWordForSuggestion( - currentSettings.mSpacingAndPunctuations, - mInputLogic.mWordComposer.isComposingWord() ? 2 : 1); - if (!TextUtils.equals(prevWordsInfo.mPrevWord, rereadPrevWordsInfo.mPrevWord)) { - throw new RuntimeException("Unexpected previous word: " - + prevWordsInfo.mPrevWord + " <> " + rereadPrevWordsInfo.mPrevWord); - } - } - } mInputLogic.mSuggest.getSuggestedWords(mInputLogic.mWordComposer, - mInputLogic.mWordComposer.getPrevWordsInfoForSuggestion(), + mInputLogic.getPrevWordsInfoFromNthPreviousWordForSuggestion( + currentSettings.mSpacingAndPunctuations, + // Get the word on which we should search the bigrams. If we are composing + // a word, it's whatever is *before* the half-committed word in the buffer, + // hence 2; if we aren't, we should just skip whitespace if any, so 1. + mInputLogic.mWordComposer.isComposingWord() ? 2 : 1), keyboard.getProximityInfo(), currentSettings.mBlockPotentiallyOffensive, currentSettings.mAutoCorrectionEnabled, additionalFeaturesOptions, sessionId, sequenceNumber, callback); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 9da0f8451..1ba5d5ea6 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -110,7 +110,7 @@ public final class Suggest { wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING, rawSuggestions); - final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); + final boolean isOnlyFirstCharCapitalized = wordComposer.isOnlyFirstCharCapitalized(); // If resumed, then we don't want to upcase everything: resuming on a fully-capitalized // words is rarely done to switch to another fully-capitalized word, but usually to a // normal, non-capitalized suggestion. @@ -122,7 +122,7 @@ public final class Suggest { } else { final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo( suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase, - isFirstCharCapitalized, trailingSingleQuotesCount); + isOnlyFirstCharCapitalized, trailingSingleQuotesCount); firstSuggestion = firstSuggestedWordInfo.mWord; if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) { whitelistedWord = null; @@ -142,7 +142,7 @@ public final class Suggest { final boolean allowsToBeAutoCorrected = (null != whitelistedWord && !whitelistedWord.equals(typedWord)) || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord( - consideredWord, wordComposer.isFirstCharCapitalized()) + consideredWord, isOnlyFirstCharCapitalized) && !typedWord.equals(firstSuggestion)); final boolean hasAutoCorrection; @@ -173,12 +173,12 @@ public final class Suggest { final ArrayList<SuggestedWordInfo> suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); - if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { + if (isOnlyFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, - trailingSingleQuotesCount); + wordInfo, suggestionResults.mLocale, isAllUpperCase, + isOnlyFirstCharCapitalized, trailingSingleQuotesCount); suggestionsContainer.set(i, transformedWordInfo); } } @@ -292,11 +292,11 @@ public final class Suggest { /* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo( final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase, - final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) { + final boolean isOnlyFirstCharCapitalized, final int trailingSingleQuotesCount) { final StringBuilder sb = new StringBuilder(wordInfo.mWord.length()); if (isAllUpperCase) { sb.append(wordInfo.mWord.toUpperCase(locale)); - } else if (isFirstCharCapitalized) { + } else if (isOnlyFirstCharCapitalized) { sb.append(StringUtils.capitalizeFirstCodePoint(wordInfo.mWord, locale)); } else { sb.append(wordInfo.mWord); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 7a50d1a9d..6ce1f85c5 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -45,9 +45,6 @@ public final class WordComposer { // The list of events that served to compose this string. private final ArrayList<Event> mEvents; private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); - // The information of previous words (before the composing word). Must not be null. Used as - // context for suggestions. - private PrevWordsInfo mPrevWordsInfo; private String mAutoCorrection; private boolean mIsResumed; private boolean mIsBatchMode; @@ -72,9 +69,9 @@ public final class WordComposer { private int mCursorPositionWithinWord; /** - * Whether the user chose to capitalize the first char of the word. + * Whether the composing word has the only first char capitalized. */ - private boolean mIsFirstCharCapitalized; + private boolean mIsOnlyFirstCharCapitalized; public WordComposer() { mCombinerChain = new CombinerChain(""); @@ -84,7 +81,6 @@ public final class WordComposer { mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; - mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; refreshTypedWordCache(); } @@ -111,12 +107,11 @@ public final class WordComposer { mAutoCorrection = null; mCapsCount = 0; mDigitsCount = 0; - mIsFirstCharCapitalized = false; + mIsOnlyFirstCharCapitalized = false; mIsResumed = false; mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; - mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; refreshTypedWordCache(); } @@ -178,12 +173,6 @@ public final class WordComposer { return mInputPointers; } - private static boolean isFirstCharCapitalized(final int index, final int codePoint, - final boolean previous) { - if (index == 0) return Character.isUpperCase(codePoint); - return previous && !Character.isUpperCase(codePoint); - } - /** * Process an input event. * @@ -203,7 +192,7 @@ public final class WordComposer { mCursorPositionWithinWord = mCodePointSize; // We may have deleted the last one. if (0 == mCodePointSize) { - mIsFirstCharCapitalized = false; + mIsOnlyFirstCharCapitalized = false; } if (Constants.CODE_DELETE != event.mKeyCode) { if (newIndex < MAX_WORD_LENGTH) { @@ -215,8 +204,12 @@ public final class WordComposer { mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); } } - mIsFirstCharCapitalized = isFirstCharCapitalized( - newIndex, primaryCode, mIsFirstCharCapitalized); + if (0 == newIndex) { + mIsOnlyFirstCharCapitalized = Character.isUpperCase(primaryCode); + } else { + mIsOnlyFirstCharCapitalized = mIsOnlyFirstCharCapitalized + && !Character.isUpperCase(primaryCode); + } if (Character.isUpperCase(primaryCode)) mCapsCount++; if (Character.isDigit(primaryCode)) mDigitsCount++; } @@ -296,10 +289,8 @@ public final class WordComposer { * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. * @param codePoints the code points to set as the composing word. * @param coordinates the x, y coordinates of the key in the CoordinateUtils format - * @param prevWordsInfo the information of previous words, to use as context for suggestions */ - public void setComposingWord(final int[] codePoints, final int[] coordinates, - final PrevWordsInfo prevWordsInfo) { + public void setComposingWord(final int[] codePoints, final int[] coordinates) { reset(); final int length = codePoints.length; for (int i = 0; i < length; ++i) { @@ -308,7 +299,6 @@ public final class WordComposer { CoordinateUtils.yFromArray(coordinates, i))); } mIsResumed = true; - mPrevWordsInfo = prevWordsInfo; } /** @@ -319,16 +309,13 @@ public final class WordComposer { return mTypedWordCache.toString(); } - public PrevWordsInfo getPrevWordsInfoForSuggestion() { - return mPrevWordsInfo; - } - /** - * Whether or not the user typed a capital letter as the first letter in the word + * Whether or not the user typed a capital letter as the first letter in the word, and no + * other letter is capitalized * @return capitalization preference */ - public boolean isFirstCharCapitalized() { - return mIsFirstCharCapitalized; + public boolean isOnlyFirstCharCapitalized() { + return mIsOnlyFirstCharCapitalized; } /** @@ -364,7 +351,7 @@ public final class WordComposer { } /** - * Saves the caps mode and the previous word at the start of composing. + * Saves the caps mode at the start of composing. * * WordComposer needs to know about the caps mode for several reasons. The first is, we need * to know after the fact what the reason was, to register the correct form into the user @@ -373,12 +360,9 @@ public final class WordComposer { * Also, batch input needs to know about the current caps mode to display correctly * capitalized suggestions. * @param mode the mode at the time of start - * @param prevWordsInfo the information of previous words */ - public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode, - final PrevWordsInfo prevWordsInfo) { + public void setCapitalizedModeAtStartComposingTime(final int mode) { mCapitalizedMode = mode; - mPrevWordsInfo = prevWordsInfo; } /** @@ -429,11 +413,10 @@ public final class WordComposer { mCapsCount = 0; mDigitsCount = 0; mIsBatchMode = false; - mPrevWordsInfo = new PrevWordsInfo(committedWord.toString()); mCombinerChain.reset(); mEvents.clear(); mCodePointSize = 0; - mIsFirstCharCapitalized = false; + mIsOnlyFirstCharCapitalized = false; mCapitalizedMode = CAPS_MODE_OFF; refreshTypedWordCache(); mAutoCorrection = null; @@ -443,15 +426,7 @@ public final class WordComposer { return lastComposedWord; } - // Call this when the recorded previous word should be discarded. This is typically called - // when the user inputs a separator that's not whitespace (including the case of the - // double-space-to-period feature). - public void discardPreviousWordForSuggestion() { - mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO; - } - - public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, - final PrevWordsInfo prevWordsInfo) { + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { mEvents.clear(); Collections.copy(mEvents, lastComposedWord.mEvents); mInputPointers.set(lastComposedWord.mInputPointers); @@ -462,7 +437,6 @@ public final class WordComposer { mCursorPositionWithinWord = mCodePointSize; mRejectedBatchModeSuggestion = null; mIsResumed = true; - mPrevWordsInfo = prevWordsInfo; } public boolean isBatchMode() { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index c90dc90ce..24cc1ef0d 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -544,11 +544,8 @@ public final class InputLogic { } } mConnection.endBatchEdit(); - mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), - // Prev word is 1st word before cursor - getPrevWordsInfoFromNthPreviousWordForSuggestion( - settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); + mWordComposer.setCapitalizedModeAtStartComposingTime( + getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode())); } /* The sequence number member is only used in onUpdateBatchInput. It is increased each time @@ -584,10 +581,8 @@ public final class InputLogic { mSpaceState = SpaceState.PHANTOM; keyboardSwitcher.requestUpdatingShiftState( getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState()); - mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(settingsValues, - keyboardSwitcher.getKeyboardShiftMode()), - new PrevWordsInfo(commitParts[0])); + mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode( + settingsValues, keyboardSwitcher.getKeyboardShiftMode())); ++mAutoCommitSequenceNumber; } } @@ -724,15 +719,7 @@ public final class InputLogic { mWordComposer.processEvent(inputTransaction.mEvent); // If it's the first letter, make note of auto-caps state if (mWordComposer.isSingleLetter()) { - // We pass 2 to getPreviousWordForSuggestion when the previous code point is a word - // connector. Otherwise, we pass 1 because we were not composing a word yet, so the - // word we want is the 1st word before the cursor. - mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - inputTransaction.mShiftState, - getPrevWordsInfoFromNthPreviousWordForSuggestion( - settingsValues.mSpacingAndPunctuations, - settingsValues.mSpacingAndPunctuations.isWordConnector( - mConnection.getCodePointBeforeCursor()) ? 2 : 1)); + mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState); } mConnection.setComposingText(getTextWithUnderline( mWordComposer.getTypedWord()), 1); @@ -924,10 +911,8 @@ public final class InputLogic { // No need to reset mSpaceState, it has already be done (that's why we // receive it as a parameter) inputTransaction.setRequiresUpdateSuggestions(); - mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - WordComposer.CAPS_MODE_OFF, - getPrevWordsInfoFromNthPreviousWordForSuggestion( - inputTransaction.mSettingsValues.mSpacingAndPunctuations, 1)); + mWordComposer.setCapitalizedModeAtStartComposingTime( + WordComposer.CAPS_MODE_OFF); return; } } else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { @@ -1107,7 +1092,6 @@ public final class InputLogic { final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations .mSentenceSeparatorAndSpace; mConnection.commitText(textToInsert, 1); - mWordComposer.discardPreviousWordForSuggestion(); return true; } return false; @@ -1267,10 +1251,7 @@ public final class InputLogic { final int expectedCursorPosition = mConnection.getExpectedSelectionStart(); if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) { // Show predictions. - mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - WordComposer.CAPS_MODE_OFF, - getPrevWordsInfoFromNthPreviousWordForSuggestion( - settingsValues.mSpacingAndPunctuations, 1)); + mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF); mLatinIME.mHandler.postUpdateSuggestionStrip(); return; } @@ -1322,7 +1303,7 @@ public final class InputLogic { settingsValues.mSpacingAndPunctuations, 0 == numberOfCharsInWordBeforeCursor ? 1 : 2); mWordComposer.setComposingWord(codePoints, - mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo); + mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); mWordComposer.setCursorPositionWithinWord( typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor)); mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, @@ -1450,7 +1431,7 @@ public final class InputLogic { // with the typed word, so we need to resume suggestions right away. final int[] codePoints = StringUtils.toCodePointArray(stringToCommit); mWordComposer.setComposingWord(codePoints, - mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo); + mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); mConnection.setComposingText(textToCommit, 1); } // Don't restart suggestion yet. We'll restart if the user deletes the separator. @@ -1897,21 +1878,6 @@ public final class InputLogic { // strings. mLastComposedWord = mWordComposer.commitWord(commitType, chosenWordWithSuggestions, separatorString, prevWordsInfo); - final boolean shouldDiscardPreviousWordForSuggestion; - if (0 == StringUtils.codePointCount(separatorString)) { - // Separator is 0-length, we can keep the previous word for suggestion. Either this - // was a manual pick or the language has no spaces in which case we want to keep the - // previous word, or it was the keyboard closing or the cursor moving in which case it - // will be reset anyway. - shouldDiscardPreviousWordForSuggestion = false; - } else { - // Otherwise, we discard if the separator contains any non-whitespace. - shouldDiscardPreviousWordForSuggestion = - !StringUtils.containsOnlyWhitespace(separatorString); - } - if (shouldDiscardPreviousWordForSuggestion) { - mWordComposer.discardPreviousWordForSuggestion(); - } } /** diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index d7953e6e7..0032fcb88 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -323,7 +323,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } else { coordinates = dictInfo.mKeyboard.getCoordinates(codePoints); } - composer.setComposingWord(codePoints, coordinates, null /* previousWord */); + composer.setComposingWord(codePoints, coordinates); // TODO: make a spell checker option to block offensive words or not final ArrayList<SuggestedWordInfo> suggestions = dictInfo.mDictionary.getSuggestions(composer, prevWordsInfo, diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 810bda758..19b48f081 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -379,10 +379,9 @@ final class SuggestionStripLayoutHelper { } else { wordView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); } - - // Disable this suggestion if the suggestion is null or empty. - // TODO: Fix disabled {@link TextView}'s content description. - wordView.setEnabled(!TextUtils.isEmpty(word)); + // {@link StyleSpan} in a content description may cause an issue of TTS/TalkBack. + // Use a simple {@link String} to avoid the issue. + wordView.setContentDescription(TextUtils.isEmpty(word) ? null : word.toString()); final CharSequence text = getEllipsizedText(word, width, wordView.getPaint()); final float scaleX = getTextScaleX(word, width, wordView.getPaint()); wordView.setText(text); // TextView.setText() resets text scale x to 1.0. @@ -461,14 +460,15 @@ final class SuggestionStripLayoutHelper { } final TextView wordView = mWordViews.get(positionInStrip); - wordView.setEnabled(true); - wordView.setTextColor(mColorAutoCorrect); + final String punctuation = punctuationSuggestions.getLabel(positionInStrip); // {@link TextView#getTag()} is used to get the index in suggestedWords at // {@link SuggestionStripView#onClick(View)}. wordView.setTag(positionInStrip); - wordView.setText(punctuationSuggestions.getLabel(positionInStrip)); + wordView.setText(punctuation); + wordView.setContentDescription(punctuation); wordView.setTextScaleX(1.0f); wordView.setCompoundDrawables(null, null, null, null); + wordView.setTextColor(mColorAutoCorrect); stripView.addView(wordView); setLayoutWeight(wordView, 1.0f, mSuggestionsStripHeight); } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 97241498a..3be933ff7 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -163,7 +163,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick word.setOnLongClickListener(this); mWordViews.add(word); final View divider = inflater.inflate(R.layout.suggestion_divider, null); - divider.setOnClickListener(this); mDividerViews.add(divider); final TextView info = new TextView(context, null, R.attr.suggestionWordStyle); info.setTextColor(Color.WHITE); @@ -429,6 +428,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick @Override public void onClick(final View view) { + AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback( + Constants.CODE_UNSPECIFIED, this); if (view == mImportantNoticeStrip) { mListener.showImportantNoticeContents(); return; diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java index 1f1475a53..0ee6236b1 100644 --- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java @@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit; import android.content.Context; import android.util.Log; +import android.util.LruCache; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.DictionaryFacilitator; @@ -36,9 +37,11 @@ public class DistracterFilterCheckingExactMatches implements DistracterFilter { private static final boolean DEBUG = false; private static final long TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS = 120; + private static final int MAX_DISTRACTERS_CACHE_SIZE = 512; private final Context mContext; private final DictionaryFacilitator mDictionaryFacilitator; + private final LruCache<String, Boolean> mDistractersCache; private final Object mLock = new Object(); /** @@ -49,6 +52,7 @@ public class DistracterFilterCheckingExactMatches implements DistracterFilter { public DistracterFilterCheckingExactMatches(final Context context) { mContext = context; mDictionaryFacilitator = new DictionaryFacilitator(); + mDistractersCache = new LruCache<>(MAX_DISTRACTERS_CACHE_SIZE); } @Override @@ -87,6 +91,7 @@ public class DistracterFilterCheckingExactMatches implements DistracterFilter { synchronized (mLock) { // Reset dictionaries for the locale. try { + mDistractersCache.evictAll(); loadDictionariesForLocale(locale); } catch (final InterruptedException e) { Log.e(TAG, "Interrupted while waiting for loading dicts in DistracterFilter", @@ -95,6 +100,15 @@ public class DistracterFilterCheckingExactMatches implements DistracterFilter { } } } + + final Boolean isCachedDistracter = mDistractersCache.get(testedWord); + if (isCachedDistracter != null && isCachedDistracter) { + if (DEBUG) { + Log.d(TAG, "testedWord: " + testedWord); + Log.d(TAG, "isDistracter: true (cache hit)"); + } + return true; + } // The tested word is a distracter when there is a word that is exact matched to the tested // word and its probability is higher than the tested word's probability. final int perfectMatchFreq = mDictionaryFacilitator.getFrequency(testedWord); @@ -106,6 +120,10 @@ public class DistracterFilterCheckingExactMatches implements DistracterFilter { Log.d(TAG, "exactMatchFreq: " + exactMatchFreq); Log.d(TAG, "isDistracter: " + isDistracter); } + if (isDistracter) { + // Add the word to the cache. + mDistractersCache.put(testedWord, Boolean.TRUE); + } return isDistracter; } } diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java index 4ed0f0a94..e4237a7f2 100644 --- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java @@ -315,24 +315,6 @@ public final class StringUtils { return true; } - /** - * Returns true if all code points in text are whitespace, false otherwise. Empty is true. - */ - // Interestingly enough, U+00A0 NO-BREAK SPACE and U+200B ZERO-WIDTH SPACE are not considered - // whitespace, while EN SPACE, EM SPACE and IDEOGRAPHIC SPACES are. - public static boolean containsOnlyWhitespace(final String text) { - final int length = text.length(); - int i = 0; - while (i < length) { - final int codePoint = text.codePointAt(i); - if (!Character.isWhitespace(codePoint)) { - return false; - } - i += Character.charCount(codePoint); - } - return true; - } - public static boolean isIdenticalAfterCapitalizeEachWord(final String text, final int[] sortedSeparators) { boolean needsCapsNext = true; |