diff options
Diffstat (limited to 'java/src')
15 files changed, 274 insertions, 180 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2e5e4c32f..d8fb4f2be 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -72,13 +72,13 @@ import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.inputlogic.InputLogic; import com.android.inputmethod.latin.inputlogic.SpaceState; import com.android.inputmethod.latin.personalization.DictionaryDecayBroadcastReciever; -import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister; +import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegistrar; +import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsActivity; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.utils.ApplicationUtils; -import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; import com.android.inputmethod.latin.utils.CompletionInfoUtils; import com.android.inputmethod.latin.utils.IntentUtils; @@ -127,8 +127,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); - private UserBinaryDictionary mUserDictionary; - // Object for reacting to adding/removing a dictionary pack. private BroadcastReceiver mDictionaryPackInstallReceiver = new DictionaryPackInstallBroadcastReceiver(this); @@ -463,7 +461,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen KeyboardSwitcher.init(this); AudioAndHapticFeedbackManager.init(this); AccessibilityUtils.init(this); - PersonalizationDictionarySessionRegister.init(this); super.onCreate(); @@ -515,10 +512,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // the layout; at this time, we need to skip resetting the contacts dictionary. It will // be done later inside {@see #initSuggest()} when the reopenDictionaries message is // processed. + final SettingsValues currentSettingsValues = mSettings.getCurrent(); if (!mHandler.hasPendingReopenDictionaries() && mInputLogic.mSuggest != null) { // May need to reset dictionaries depending on the user settings. + // TODO: Quit setting dictionaries from LatinIME. mInputLogic.mSuggest.setAdditionalDictionaries(mInputLogic.mSuggest /* oldSuggest */, - mSettings.getCurrent()); + currentSettingsValues); + } + if (currentSettingsValues.mUsePersonalizedDicts) { + PersonalizationDictionarySessionRegistrar.init(this); + } else { + PersonalizationHelper.removeAllPersonalizedDictionaries(this); + PersonalizationDictionarySessionRegistrar.resetAll(this); } } @@ -548,9 +553,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen subtypeLocale = switcherSubtypeLocale; } - final Suggest newSuggest = new Suggest(this /* Context */, subtypeLocale, - this /* SuggestInitializationListener */); final SettingsValues settingsValues = mSettings.getCurrent(); + final Suggest newSuggest = new Suggest(this /* Context */, subtypeLocale, settingsValues, + this /* SuggestInitializationListener */); if (settingsValues.mCorrectionEnabled) { newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold); } @@ -558,11 +563,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.getInstance().initSuggest(newSuggest); } - - mUserDictionary = new UserBinaryDictionary(this, subtypeLocale); - newSuggest.setUserDictionary(mUserDictionary); - newSuggest.setAdditionalDictionaries(mInputLogic.mSuggest /* oldSuggest */, - mSettings.getCurrent()); + // TODO: Quit setting dictionaries from LatinIME. + newSuggest.setAdditionalDictionaries(mInputLogic.mSuggest /* oldSuggest */, settingsValues); final Suggest oldSuggest = mInputLogic.mSuggest; mInputLogic.mSuggest = newSuggest; if (oldSuggest != null) oldSuggest.close(); @@ -590,7 +592,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ResearchLogger.getInstance().onDestroy(); } unregisterReceiver(mDictionaryPackInstallReceiver); - PersonalizationDictionarySessionRegister.onDestroy(this); + PersonalizationDictionarySessionRegistrar.onDestroy(this); LatinImeLogger.commit(); LatinImeLogger.onDestroy(); super.onDestroy(); @@ -610,7 +612,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mOptionsDialog.dismiss(); } } - PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf); + PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf); super.onConfigurationChanged(conf); } @@ -1145,7 +1147,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean onEvaluateFullscreenMode() { - // Reread resource value here, because this method is called by framework anytime as needed. + // Reread resource value here, because this method is called by the framework as needed. final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI @@ -1201,7 +1203,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { wordToEdit = word; } - mUserDictionary.addWordToUserDictionary(wordToEdit); + mInputLogic.mSuggest.addWordToUserDictionary(wordToEdit); } public void displaySettingsDialog() { @@ -1270,7 +1272,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onCancelBatchInput() { - mInputLogic.onCancelBatchInput(mInputUpdater); + mInputLogic.onCancelBatchInput(mHandler, mInputUpdater); } // TODO[IL]: Make this a package-private standalone class in inputlogic/ and remove all @@ -1308,17 +1310,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return true; } - // Run in the UI thread. + // Run on the UI thread. public void onStartBatchInput() { synchronized (mLock) { mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); mInBatchInput = true; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); } } - // Run in the Handler thread. + // Run on the Handler thread. private void updateBatchInput(final InputPointers batchPointers, final int sequenceNumber) { synchronized (mLock) { if (!mInBatchInput) { @@ -1337,7 +1337,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - // Run in the UI thread. + // Run on the UI thread. public void onUpdateBatchInput(final InputPointers batchPointers, final int sequenceNumber) { if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) { @@ -1350,12 +1350,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onCancelBatchInput() { synchronized (mLock) { mInBatchInput = false; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); } } - // Run in the UI thread. + // Run on the UI thread. public void onEndBatchInput(final InputPointers batchPointers) { synchronized(mLock) { getSuggestedWordsGestureLocked(batchPointers, SuggestedWords.NOT_A_SEQUENCE_NUMBER, @@ -1405,7 +1403,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - // This method must run in UI Thread. + // This method must run on the UI Thread. private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, final boolean dismissGestureFloatingPreviewText) { showSuggestionStrip(suggestedWords); @@ -1416,7 +1414,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - // This method must run in UI Thread. + // This method must run on the UI Thread. public void onEndBatchInputAsyncInternal(final SuggestedWords suggestedWords) { final String batchInputText = suggestedWords.isEmpty() ? null : suggestedWords.getWord(0); if (TextUtils.isEmpty(batchInputText)) { @@ -1613,19 +1611,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen false /* isPrediction */); } - private void setAutoCorrection(final SuggestedWords suggestedWords, final String typedWord) { - if (suggestedWords.isEmpty()) return; - final String autoCorrection; - if (suggestedWords.mWillAutoCorrect) { - autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); - } else { - // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD) - // because it may differ from mWordComposer.mTypedWord. - autoCorrection = typedWord; - } - mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); - } - private void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords, final String typedWord) { if (suggestedWords.isEmpty()) { @@ -1634,10 +1619,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen clearSuggestionStrip(); return; } - setAutoCorrection(suggestedWords, typedWord); - final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); - setSuggestedWords(suggestedWords, isAutoCorrection); - setAutoCorrectionIndicator(isAutoCorrection); + final String autoCorrection; + if (suggestedWords.mWillAutoCorrect) { + autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); + } else { + // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD) + // because it may differ from mWordComposer.mTypedWord. + autoCorrection = typedWord; + } + mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); + setSuggestedWords(suggestedWords, suggestedWords.mWillAutoCorrect); + setAutoCorrectionIndicator(suggestedWords.mWillAutoCorrect); setSuggestionStripShown(isSuggestionsStripVisible()); // An auto-correction is available, cache it in accessibility code so // we can be speak it if the user touches a key that will insert it. @@ -1732,13 +1724,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen || SuggestedWordInfo.KIND_OOV_CORRECTION == suggestionInfo.mKind) && suggest != null // If the suggestion is not in the dictionary, the hint should be shown. - && !AutoCorrectionUtils.isValidWord(suggest, suggestion, true); + && !suggest.isValidWord(suggestion, true); if (currentSettings.mIsInternal) { LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } - if (showingAddToDictionaryHint && mUserDictionary.mEnabled) { + if (showingAddToDictionaryHint && suggest.isUserDictionaryEnabled()) { mSuggestionStripView.showAddToDictionaryHint( suggestion, currentSettings.mHintToSaveText); } else { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 32ab1f3df..16841224f 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -17,7 +17,6 @@ package com.android.inputmethod.latin; import android.content.Context; -import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; @@ -27,7 +26,6 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.personalization.PersonalizationDictionary; import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.personalization.UserHistoryDictionary; -import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.BoundedTreeSet; @@ -39,11 +37,13 @@ import java.util.Comparator; import java.util.HashSet; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; /** * This class loads a dictionary and provides a list of suggestions for a given sequence of * characters. This includes corrections and completions. */ +// TODO: Separate dictionary operations from suggestions handling logic. public final class Suggest { public static final String TAG = Suggest.class.getSimpleName(); @@ -74,6 +74,7 @@ public final class Suggest { private HashSet<String> mOnlyDictionarySetForDebug = null; private Dictionary mMainDictionary; private ContactsBinaryDictionary mContactsDictionary; + private UserBinaryDictionary mUserDictionary; private UserHistoryDictionary mUserHistoryDictionary; private PersonalizationDictionary mPersonalizationDictionary; @UsedForTesting @@ -86,18 +87,17 @@ public final class Suggest { private final Context mContext; - public Suggest(final Context context, final Locale locale, + public Suggest(final Context context, final Locale locale, final SettingsValues settingsValues, final SuggestInitializationListener listener) { initAsynchronously(context, locale, listener); mLocale = locale; mContext = context; - // TODO: Use SettingsValues instead of Settings. // initialize a debug flag for the personalization - if (Settings.readUseOnlyPersonalizationDictionaryForDebug( - PreferenceManager.getDefaultSharedPreferences(context))) { + if (settingsValues.mUseOnlyPersonalizationDictionaryForDebug) { mOnlyDictionarySetForDebug = new HashSet<String>(); mOnlyDictionarySetForDebug.add(Dictionary.TYPE_PERSONALIZATION); } + setUserDictionary(new UserBinaryDictionary(context, locale)); } @UsedForTesting @@ -171,27 +171,13 @@ public final class Suggest { return mMainDictionary; } - public ContactsBinaryDictionary getContactsDictionary() { - return mContactsDictionary; - } - - public UserHistoryDictionary getUserHistoryDictionary() { - return mUserHistoryDictionary; - } - - public PersonalizationDictionary getPersonalizationDictionary() { - return mPersonalizationDictionary; - } - - public ConcurrentHashMap<String, Dictionary> getUnigramDictionaries() { - return mDictionaries; - } - /** * Sets an optional user dictionary resource to be loaded. The user dictionary is consulted * before the main dictionary, if set. This refers to the system-managed user dictionary. */ + @UsedForTesting public void setUserDictionary(final UserBinaryDictionary userDictionary) { + mUserDictionary = userDictionary; addOrReplaceDictionaryInternal(Dictionary.TYPE_USER, userDictionary); } @@ -200,17 +186,18 @@ public final class Suggest { * the contacts dictionary by passing null to this method. In this case no contacts dictionary * won't be used. */ + @UsedForTesting public void setContactsDictionary(final ContactsBinaryDictionary contactsDictionary) { mContactsDictionary = contactsDictionary; addOrReplaceDictionaryInternal(Dictionary.TYPE_CONTACTS, contactsDictionary); } - public void setUserHistoryDictionary(final UserHistoryDictionary userHistoryDictionary) { + private void setUserHistoryDictionary(final UserHistoryDictionary userHistoryDictionary) { mUserHistoryDictionary = userHistoryDictionary; addOrReplaceDictionaryInternal(Dictionary.TYPE_USER_HISTORY, userHistoryDictionary); } - public void setPersonalizationDictionary( + private void setPersonalizationDictionary( final PersonalizationDictionary personalizationDictionary) { mPersonalizationDictionary = personalizationDictionary; addOrReplaceDictionaryInternal(Dictionary.TYPE_PERSONALIZATION, personalizationDictionary); @@ -225,7 +212,7 @@ public final class Suggest { public void setAdditionalDictionaries(final Suggest oldSuggest, final SettingsValues settingsValues) { // Contacts dictionary - resetContactsDictionary(null != oldSuggest ? oldSuggest.getContactsDictionary() : null, + resetContactsDictionary(null != oldSuggest ? oldSuggest.mContactsDictionary : null, settingsValues); // User history dictionary & Personalization dictionary resetPersonalizedDictionaries(oldSuggest, settingsValues); @@ -245,9 +232,9 @@ public final class Suggest { final boolean shouldSetDictionaries = settingsValues.mUsePersonalizedDicts; final UserHistoryDictionary oldUserHistoryDictionary = (null == oldSuggest) ? null : - oldSuggest.getUserHistoryDictionary(); + oldSuggest.mUserHistoryDictionary; final PersonalizationDictionary oldPersonalizationDictionary = (null == oldSuggest) ? null : - oldSuggest.getPersonalizationDictionary(); + oldSuggest.mPersonalizationDictionary; final UserHistoryDictionary userHistoryDictionaryToUse; final PersonalizationDictionary personalizationDictionaryToUse; if (!shouldSetDictionaries) { @@ -311,6 +298,43 @@ public final class Suggest { setContactsDictionary(dictionaryToUse); } + public boolean isUserDictionaryEnabled() { + if (mUserDictionary == null) { + return false; + } + return mUserDictionary.mEnabled; + } + + public void addWordToUserDictionary(String word) { + if (mUserDictionary == null) { + return; + } + mUserDictionary.addWordToUserDictionary(word); + } + + public String addToUserHistory(final WordComposer wordComposer, final String previousWord, + final String suggestion) { + if (mUserHistoryDictionary == null) { + return null; + } + final String secondWord; + if (wordComposer.wasAutoCapitalized() && !wordComposer.isMostlyCaps()) { + secondWord = suggestion.toLowerCase(mLocale); + } else { + secondWord = suggestion; + } + // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". + // We don't add words with 0-frequency (assuming they would be profanity etc.). + final int maxFreq = getMaxFrequency(suggestion); + if (maxFreq == 0) { + return null; + } + final boolean isValid = maxFreq > 0; + final int timeStamp = (int)TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis())); + mUserHistoryDictionary.addToDictionary(previousWord, secondWord, isValid, timeStamp); + return previousWord; + } + public void cancelAddingUserHistory(final String previousWord, final String committedWord) { if (mUserHistoryDictionary != null) { mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord); @@ -389,8 +413,8 @@ public final class Suggest { // or if it's a 2+ characters non-word (i.e. it's not in the dictionary). final boolean allowsToBeAutoCorrected = (null != whitelistedWord && !whitelistedWord.equals(consideredWord)) - || (consideredWord.length() > 1 && !AutoCorrectionUtils.isValidWord(this, - consideredWord, wordComposer.isFirstCharCapitalized())); + || (consideredWord.length() > 1 + && !isValidWord(consideredWord, wordComposer.isFirstCharCapitalized())); final boolean hasAutoCorrection; // TODO: using isCorrectionEnabled here is not very good. It's probably useless, because @@ -594,6 +618,45 @@ public final class Suggest { wordInfo.mAutoCommitFirstWordConfidence); } + public boolean isValidWord(final String word, final boolean ignoreCase) { + if (TextUtils.isEmpty(word)) { + return false; + } + final String lowerCasedWord = word.toLowerCase(mLocale); + for (final String key : mDictionaries.keySet()) { + final Dictionary dictionary = mDictionaries.get(key); + // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow + // managing to get null in here. Presumably the language is changing to a language with + // no main dictionary and the monkey manages to type a whole word before the thread + // that reads the dictionary is started or something? + // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and + // would be immutable once it's finished initializing, but concretely a null test is + // probably good enough for the time being. + if (null == dictionary) continue; + if (dictionary.isValidWord(word) + || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { + return true; + } + } + return false; + } + + private int getMaxFrequency(final String word) { + if (TextUtils.isEmpty(word)) { + return Dictionary.NOT_A_PROBABILITY; + } + int maxFreq = -1; + for (final String key : mDictionaries.keySet()) { + final Dictionary dictionary = mDictionaries.get(key); + if (null == dictionary) continue; + final int tempFreq = dictionary.getFrequency(word); + if (tempFreq >= maxFreq) { + maxFreq = tempFreq; + } + } + return maxFreq; + } + public void close() { final HashSet<Dictionary> dictionaries = CollectionUtils.newHashSet(); dictionaries.addAll(mDictionaries.values()); diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 97c89dd4e..f9de89c80 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -104,10 +104,6 @@ public final class SuggestedWords { return debugString; } - public boolean willAutoCorrect() { - return mWillAutoCorrect; - } - @Override public String toString() { // Pretty-print method to help debug @@ -150,7 +146,7 @@ public final class SuggestedWords { for (int index = 1; index < previousSize; index++) { final SuggestedWordInfo prevWordInfo = previousSuggestions.getInfo(index); final String prevWord = prevWordInfo.mWord; - // Filter out duplicate suggestion. + // Filter out duplicate suggestions. if (!alreadySeen.contains(prevWord)) { suggestionsList.add(prevWordInfo); alreadySeen.add(prevWord); diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index df34687e3..4a4abd7d2 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -44,12 +44,10 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethod.latin.personalization.UserHistoryDictionary; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.utils.AsyncResultHolder; -import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.InputTypeUtils; import com.android.inputmethod.latin.utils.LatinImeLoggerUtils; @@ -60,7 +58,6 @@ import com.android.inputmethod.research.ResearchLogger; import java.util.ArrayList; import java.util.TreeSet; -import java.util.concurrent.TimeUnit; /** * This class manages the input logic. @@ -71,6 +68,8 @@ public final class InputLogic { // TODO : Remove this member when we can. private final LatinIME mLatinIME; + private InputLogicHandler mInputLogicHandler; + // TODO : make all these fields private as soon as possible. // Current space state of the input method. This can be any of the above constants. public int mSpaceState; @@ -105,6 +104,7 @@ public final class InputLogic { mWordComposer = new WordComposer(); mEventInterpreter = new EventInterpreter(latinIME); mConnection = new RichInputConnection(latinIME); + mInputLogicHandler = null; } /** @@ -119,12 +119,15 @@ public final class InputLogic { * @param restarting whether input is starting in the same field as before. */ public void startInput(final boolean restarting) { + mInputLogicHandler = new InputLogicHandler(); } /** * Clean up the input logic after input is finished. */ public void finishInput() { + mInputLogicHandler.destroy(); + mInputLogicHandler = null; } /** @@ -300,6 +303,8 @@ public final class InputLogic { final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler, final LatinIME.InputUpdater inputUpdater) { inputUpdater.onStartBatchInput(); + handler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); handler.cancelUpdateSuggestionStrip(); mConnection.beginBatchEdit(); if (mWordComposer.isComposingWord()) { @@ -400,9 +405,12 @@ public final class InputLogic { inputUpdater.onEndBatchInput(batchPointers); } - // TODO: remove this argument - public void onCancelBatchInput(final LatinIME.InputUpdater inputUpdater) { + // TODO: remove these arguments + public void onCancelBatchInput(final LatinIME.UIHandler handler, + final LatinIME.InputUpdater inputUpdater) { inputUpdater.onCancelBatchInput(); + handler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); } /** @@ -977,24 +985,8 @@ public final class InputLogic { final Suggest suggest = mSuggest; if (suggest == null) return null; - final UserHistoryDictionary userHistoryDictionary = suggest.getUserHistoryDictionary(); - if (userHistoryDictionary == null) return null; - final String prevWord = mConnection.getNthPreviousWord(settingsValues, 2); - final String secondWord; - if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { - secondWord = suggestion.toLowerCase(settingsValues.mLocale); - } else { - secondWord = suggestion; - } - // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". - // We don't add words with 0-frequency (assuming they would be profanity etc.). - final int maxFreq = AutoCorrectionUtils.getMaxFrequency( - suggest.getUnigramDictionaries(), suggestion); - if (maxFreq == 0) return null; - userHistoryDictionary.addToDictionary(prevWord, secondWord, maxFreq > 0, - (int)TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis()))); - return prevWord; + return suggest.addToUserHistory(mWordComposer, prevWord, suggestion); } public void performUpdateSuggestionStripSync(final SettingsValues settingsValues, diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java new file mode 100644 index 000000000..d611e4bf8 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 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.inputlogic; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; + +/** + * A helper to manage deferred tasks for the input logic. + */ +// TODO: Make this package private +public class InputLogicHandler implements Handler.Callback { + final Handler mNonUIThreadHandler; + + public InputLogicHandler() { + final HandlerThread handlerThread = new HandlerThread( + InputLogicHandler.class.getSimpleName()); + handlerThread.start(); + mNonUIThreadHandler = new Handler(handlerThread.getLooper(), this); + } + + public void destroy() { + mNonUIThreadHandler.getLooper().quit(); + } + + /** + * Handle a message. + * @see android.os.Handler.Callback#handleMessage(android.os.Message) + */ + @Override + public boolean handleMessage(final Message msg) { + return true; + } +} diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java index 596562f1d..9b2b981d5 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java @@ -27,7 +27,7 @@ import java.util.Locale; import android.content.Context; public class PersonalizationDictionary extends DecayingExpandableBinaryDictionaryBase { - private static final String NAME = PersonalizationDictionary.class.getSimpleName(); + /* package */ static final String NAME = PersonalizationDictionary.class.getSimpleName(); private final ArrayList<PersonalizationDictionaryUpdateSession> mSessions = CollectionUtils.newArrayList(); diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java index 542bda621..76965112f 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java @@ -19,7 +19,7 @@ package com.android.inputmethod.latin.personalization; import android.content.Context; import android.content.res.Configuration; -public class PersonalizationDictionarySessionRegister { +public class PersonalizationDictionarySessionRegistrar { public static void init(final Context context) { } @@ -32,6 +32,9 @@ public class PersonalizationDictionarySessionRegister { public static void onRemoveData(final Context context, final String type) { } + public static void resetAll(final Context context) { + } + public static void onDestroy(final Context context) { } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index d55cae132..38b22e5f6 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -17,10 +17,13 @@ package com.android.inputmethod.latin.personalization; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import android.content.Context; import android.util.Log; +import java.io.File; +import java.io.FilenameFilter; import java.lang.ref.SoftReference; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; @@ -96,4 +99,47 @@ public class PersonalizationHelper { return dict; } } + + public static void removeAllPersonalizedDictionaries(final Context context) { + removeAllDictionaries(context, sLangUserHistoryDictCache, + UserHistoryDictionary.NAME); + removeAllDictionaries(context, sLangPersonalizationDictCache, + PersonalizationDictionary.NAME); + } + + private static <T extends DecayingExpandableBinaryDictionaryBase> void removeAllDictionaries( + final Context context, final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap, + final String dictNamePrefix) { + synchronized (dictionaryMap) { + for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry + : dictionaryMap.entrySet()) { + if (entry.getValue() != null) { + final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get(); + if (dict != null) { + dict.clearAndFlushDictionary(); + } + } + } + dictionaryMap.clear(); + if (!FileUtils.deleteFilteredFiles( + context.getFilesDir(), new DictFilter(dictNamePrefix))) { + Log.e(TAG, "Cannot remove all existing dictionary files. filesDir: " + + context.getFilesDir().getAbsolutePath() + ", dictNamePrefix: " + + dictNamePrefix); + } + } + } + + private static class DictFilter implements FilenameFilter { + private final String mName; + + DictFilter(final String name) { + mName = name; + } + + @Override + public boolean accept(final File dir, final String name) { + return name.startsWith(mName); + } + } } diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java index 868f21cbc..c23bc9bc0 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -29,8 +29,7 @@ import android.content.Context; * cancellation or manual picks. This allows the keyboard to adapt to the typist over time. */ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase { - /* package for tests */ static final String NAME = - UserHistoryDictionary.class.getSimpleName(); + /* package */ static final String NAME = UserHistoryDictionary.class.getSimpleName(); /* package */ UserHistoryDictionary(final Context context, final Locale locale) { super(context, locale, Dictionary.TYPE_USER_HISTORY, getDictNameWithLocale(NAME, locale)); } diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index d060485bd..29bbed8bd 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -39,8 +39,6 @@ public final class DebugSettings extends PreferenceFragment public static final String PREF_STATISTICS_LOGGING = "enable_logging"; public static final String PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG = "use_only_personalization_dictionary_for_debug"; - public static final String PREF_BOOST_PERSONALIZATION_DICTIONARY_FOR_DEBUG = - "boost_personalization_dictionary_for_debug"; private static final String PREF_READ_EXTERNAL_DICTIONARY = "read_external_dictionary"; private static final boolean SHOW_STATISTICS_LOGGING = false; diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 9bd2b9389..75c7258ae 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -358,21 +358,13 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return prefs.getBoolean(Settings.PREF_KEY_IS_INTERNAL, false); } - public static boolean readUseOnlyPersonalizationDictionaryForDebug( - final SharedPreferences prefs) { - return prefs.getBoolean( - DebugSettings.PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false); - } - - public static boolean readBoostPersonalizationDictionaryForDebug( - final SharedPreferences prefs) { - return prefs.getBoolean( - DebugSettings.PREF_BOOST_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false); - } - public void writeLastUsedPersonalizationToken(byte[] token) { - final String tokenStr = StringUtils.byteArrayToHexString(token); - mPrefs.edit().putString(PREF_LAST_USED_PERSONALIZATION_TOKEN, tokenStr).apply(); + if (token == null) { + mPrefs.edit().remove(PREF_LAST_USED_PERSONALIZATION_TOKEN).apply(); + } else { + final String tokenStr = StringUtils.byteArrayToHexString(token); + mPrefs.edit().putString(PREF_LAST_USED_PERSONALIZATION_TOKEN, tokenStr).apply(); + } } public byte[] readLastUsedPersonalizationToken() { diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 3307de8ae..a07a0cecf 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -99,7 +99,6 @@ public final class SettingsValues { public final float mAutoCorrectionThreshold; public final boolean mCorrectionEnabled; public final int mSuggestionVisibility; - public final boolean mBoostPersonalizationDictionaryForDebug; public final boolean mUseOnlyPersonalizationDictionaryForDebug; public final int mDisplayOrientation; private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds; @@ -181,10 +180,8 @@ public final class SettingsValues { AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray( prefs, mAdditionalFeaturesSettingValues); mIsInternal = Settings.isInternal(prefs); - mBoostPersonalizationDictionaryForDebug = - Settings.readBoostPersonalizationDictionaryForDebug(prefs); - mUseOnlyPersonalizationDictionaryForDebug = - Settings.readUseOnlyPersonalizationDictionaryForDebug(prefs); + mUseOnlyPersonalizationDictionaryForDebug = prefs.getBoolean( + DebugSettings.PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false); mDisplayOrientation = res.getConfiguration().orientation; mAppWorkarounds = new AsyncResultHolder<AppWorkaroundsUtils>(); final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo( @@ -241,7 +238,6 @@ public final class SettingsValues { mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; mSuggestionVisibility = 0; mIsInternal = false; - mBoostPersonalizationDictionaryForDebug = false; mUseOnlyPersonalizationDictionaryForDebug = false; mDisplayOrientation = Configuration.ORIENTATION_PORTRAIT; mAppWorkarounds = new AsyncResultHolder<AppWorkaroundsUtils>(); @@ -321,7 +317,7 @@ public final class SettingsValues { public boolean isBrokenByRecorrection() { final AppWorkaroundsUtils appWorkaroundUtils = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); - return null == appWorkaroundUtils ? null : appWorkaroundUtils.isBrokenByRecorrection(); + return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBrokenByRecorrection(); } // Helper functions to create member values. diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 72281e62c..f836e61cb 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -208,7 +208,7 @@ final class SuggestionStripLayoutHelper { } final String word = suggestedWords.getWord(indexInSuggestedWords); final boolean isAutoCorrect = indexInSuggestedWords == 1 - && suggestedWords.willAutoCorrect(); + && suggestedWords.mWillAutoCorrect; final boolean isTypedWordValid = indexInSuggestedWords == 0 && suggestedWords.mTypedWordValid; if (!isAutoCorrect && !isTypedWordValid) { @@ -232,7 +232,7 @@ final class SuggestionStripLayoutHelper { final SuggestedWords suggestedWords) { final int indexToDisplayMostImportantSuggestion; final int indexToDisplaySecondMostImportantSuggestion; - if (suggestedWords.willAutoCorrect()) { + if (suggestedWords.mWillAutoCorrect) { indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION; indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD; } else { @@ -257,7 +257,7 @@ final class SuggestionStripLayoutHelper { final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD); final int color; - if (positionInStrip == mCenterPositionInStrip && suggestedWords.willAutoCorrect()) { + if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) { color = mColorAutoCorrect; } else if (positionInStrip == mCenterPositionInStrip && suggestedWords.mTypedWordValid) { color = mColorValidTypedWord; diff --git a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java index 066c5fd32..37c173f96 100644 --- a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java @@ -17,16 +17,11 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.latin.BinaryDictionary; -import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import android.text.TextUtils; import android.util.Log; -import java.util.concurrent.ConcurrentHashMap; - public final class AutoCorrectionUtils { private static final boolean DBG = LatinImeLogger.sDBG; private static final String TAG = AutoCorrectionUtils.class.getSimpleName(); @@ -36,48 +31,6 @@ public final class AutoCorrectionUtils { // Purely static class: can't instantiate. } - public static boolean isValidWord(final Suggest suggest, final String word, - final boolean ignoreCase) { - if (TextUtils.isEmpty(word)) { - return false; - } - final ConcurrentHashMap<String, Dictionary> dictionaries = suggest.getUnigramDictionaries(); - final String lowerCasedWord = word.toLowerCase(suggest.mLocale); - for (final String key : dictionaries.keySet()) { - final Dictionary dictionary = dictionaries.get(key); - // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow - // managing to get null in here. Presumably the language is changing to a language with - // no main dictionary and the monkey manages to type a whole word before the thread - // that reads the dictionary is started or something? - // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and - // would be immutable once it's finished initializing, but concretely a null test is - // probably good enough for the time being. - if (null == dictionary) continue; - if (dictionary.isValidWord(word) - || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { - return true; - } - } - return false; - } - - public static int getMaxFrequency(final ConcurrentHashMap<String, Dictionary> dictionaries, - final String word) { - if (TextUtils.isEmpty(word)) { - return Dictionary.NOT_A_PROBABILITY; - } - int maxFreq = -1; - for (final String key : dictionaries.keySet()) { - final Dictionary dictionary = dictionaries.get(key); - if (null == dictionary) continue; - final int tempFreq = dictionary.getFrequency(word); - if (tempFreq >= maxFreq) { - maxFreq = tempFreq; - } - } - return maxFreq; - } - public static boolean suggestionExceedsAutoCorrectionThreshold( final SuggestedWordInfo suggestion, final String consideredWord, final float autoCorrectionThreshold) { diff --git a/java/src/com/android/inputmethod/latin/utils/FileUtils.java b/java/src/com/android/inputmethod/latin/utils/FileUtils.java index 83c1e7c4d..22b0fbbcd 100644 --- a/java/src/com/android/inputmethod/latin/utils/FileUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/FileUtils.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin.utils; import java.io.File; +import java.io.FilenameFilter; /** * A simple class to help with removing directories recursively. @@ -30,4 +31,18 @@ public class FileUtils { } return path.delete(); } + + public static boolean deleteFilteredFiles(final File dir, final FilenameFilter fileNameFilter) { + if (!dir.isDirectory()) { + return false; + } + final File[] files = dir.listFiles(fileNameFilter); + boolean hasDeletedAllFiles = true; + for (final File file : files) { + if (!deleteRecursively(file)) { + hasDeletedAllFiles = false; + } + } + return hasDeletedAllFiles; + } } |