aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java629
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java127
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java87
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java39
-rw-r--r--java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java49
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SuggestionResults.java76
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java5
8 files changed, 468 insertions, 546 deletions
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index d6178fcee..8b8d5776e 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -26,15 +26,14 @@ 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.SettingsValues;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ExecutorUtils;
import com.android.inputmethod.latin.utils.LanguageModelParam;
+import com.android.inputmethod.latin.utils.SuggestionResults;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -50,197 +49,314 @@ public class DictionaryFacilitatorForSuggest {
// dictionary.
private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140;
- private final Context mContext;
- public final Locale mLocale;
+ private Dictionaries mDictionaries = new Dictionaries();
+ private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
+ // To synchronize assigning mDictionaries to ensure closing dictionaries.
+ private Object mLock = new Object();
- private final ConcurrentHashMap<String, Dictionary> mDictionaries =
- CollectionUtils.newConcurrentHashMap();
+ /**
+ * Class contains dictionaries for a locale.
+ */
+ private static class Dictionaries {
+ public final Locale mLocale;
+ public final ConcurrentHashMap<String, Dictionary> mDictMap =
+ CollectionUtils.newConcurrentHashMap();
+ // Main dictionary will be asynchronously loaded.
+ public Dictionary mMainDictionary;
+ public final ContactsBinaryDictionary mContactsDictionary;
+ public final UserBinaryDictionary mUserDictionary;
+ public final UserHistoryDictionary mUserHistoryDictionary;
+ public final PersonalizationDictionary mPersonalizationDictionary;
+
+ public Dictionaries() {
+ mLocale = null;
+ mMainDictionary = null;
+ mContactsDictionary = null;
+ mUserDictionary = null;
+ mUserHistoryDictionary = null;
+ mPersonalizationDictionary = null;
+ }
+
+ public Dictionaries(final Locale locale, final Dictionary mainDict,
+ final ContactsBinaryDictionary contactsDict, final UserBinaryDictionary userDict,
+ final UserHistoryDictionary userHistoryDict,
+ final PersonalizationDictionary personalizationDict) {
+ mLocale = locale;
+ setMainDict(mainDict);
+ mContactsDictionary = contactsDict;
+ if (mContactsDictionary != null) {
+ mDictMap.put(Dictionary.TYPE_CONTACTS, mContactsDictionary);
+ }
+ mUserDictionary = userDict;
+ if (mUserDictionary != null) {
+ mDictMap.put(Dictionary.TYPE_USER, mUserDictionary);
+ }
+ mUserHistoryDictionary = userHistoryDict;
+ if (mUserHistoryDictionary != null) {
+ mDictMap.put(Dictionary.TYPE_USER_HISTORY, mUserHistoryDictionary);
+ }
+ mPersonalizationDictionary = personalizationDict;
+ if (mPersonalizationDictionary != null) {
+ mDictMap.put(Dictionary.TYPE_PERSONALIZATION, mPersonalizationDictionary);
+ }
+ }
+
+ public void setMainDict(final Dictionary mainDict) {
+ mMainDictionary = mainDict;
+ // Close old dictionary if exists. Main dictionary can be assigned multiple times.
+ final Dictionary oldDict;
+ if (mMainDictionary != null) {
+ oldDict = mDictMap.put(Dictionary.TYPE_MAIN, mMainDictionary);
+ } else {
+ oldDict = mDictMap.remove(Dictionary.TYPE_MAIN);
+ }
+ if (oldDict != null && mMainDictionary != oldDict) {
+ oldDict.close();
+ }
+ }
+
+ public boolean hasMainDict() {
+ return mMainDictionary != null;
+ }
- private Dictionary mMainDictionary;
- private ContactsBinaryDictionary mContactsDictionary;
- private UserBinaryDictionary mUserDictionary;
- private UserHistoryDictionary mUserHistoryDictionary;
- private PersonalizationDictionary mPersonalizationDictionary;
+ public boolean hasContactsDict() {
+ return mContactsDictionary != null;
+ }
+
+ public boolean hasUserDict() {
+ return mUserDictionary != null;
+ }
+
+ public boolean hasUserHistoryDict() {
+ return mUserHistoryDictionary != null;
+ }
- private final CountDownLatch mLatchForWaitingLoadingMainDictionary;
+ public boolean hasPersonalizationDict() {
+ return mPersonalizationDictionary != null;
+ }
+ }
public interface DictionaryInitializationListener {
public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable);
}
- /**
- * Creates instance for initialization or when the locale is changed.
- *
- * @param context the context
- * @param locale the locale
- * @param settingsValues current settings values to control what dictionaries should be used
- * @param listener the listener
- * @param oldDictionaryFacilitator the instance having old dictionaries. This is null when the
- * instance is initially created.
- */
- public DictionaryFacilitatorForSuggest(final Context context, final Locale locale,
- final SettingsValues settingsValues, final DictionaryInitializationListener listener,
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
- mContext = context;
- mLocale = locale;
- mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1);
- loadMainDict(context, locale, listener);
- setUserDictionary(new UserBinaryDictionary(context, locale));
- resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
+ public DictionaryFacilitatorForSuggest() {}
+
+ public Locale getLocale() {
+ return mDictionaries.mLocale;
}
- /**
- * Creates instance for reloading the main dict.
- *
- * @param listener the listener
- * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null.
- */
- public DictionaryFacilitatorForSuggest(final DictionaryInitializationListener listener,
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
- mContext = oldDictionaryFacilitator.mContext;
- mLocale = oldDictionaryFacilitator.mLocale;
- mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1);
- loadMainDict(mContext, mLocale, listener);
- // Transfer user dictionary.
- setUserDictionary(oldDictionaryFacilitator.mUserDictionary);
- oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER);
- // Transfer contacts dictionary.
- setContactsDictionary(oldDictionaryFacilitator.mContactsDictionary);
- oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_CONTACTS);
- // Transfer user history dictionary.
- setUserHistoryDictionary(oldDictionaryFacilitator.mUserHistoryDictionary);
- oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER_HISTORY);
- // Transfer personalization dictionary.
- setPersonalizationDictionary(oldDictionaryFacilitator.mPersonalizationDictionary);
- oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_PERSONALIZATION);
+ public void resetDictionaries(final Context context, final Locale newLocale,
+ final boolean useContactsDict, final boolean usePersonalizedDicts,
+ final boolean forceReloadMainDictionary,
+ final DictionaryInitializationListener listener) {
+ final boolean localeHasBeenChanged = !newLocale.equals(mDictionaries.mLocale);
+ // We always try to have the main dictionary. Other dictionaries can be unused.
+ final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary;
+ final boolean closeContactsDictionary = localeHasBeenChanged || !useContactsDict;
+ final boolean closeUserDictionary = localeHasBeenChanged;
+ final boolean closeUserHistoryDictionary = localeHasBeenChanged || !usePersonalizedDicts;
+ final boolean closePersonalizationDictionary =
+ localeHasBeenChanged || !usePersonalizedDicts;
+
+ final Dictionary newMainDict;
+ if (reloadMainDictionary) {
+ // The main dictionary will be asynchronously loaded.
+ newMainDict = null;
+ } else {
+ newMainDict = mDictionaries.mMainDictionary;
+ }
+
+ // Open or move contacts dictionary.
+ final ContactsBinaryDictionary newContactsDict;
+ if (!closeContactsDictionary && mDictionaries.hasContactsDict()) {
+ newContactsDict = mDictionaries.mContactsDictionary;
+ } else if (useContactsDict) {
+ newContactsDict = new ContactsBinaryDictionary(context, newLocale);
+ } else {
+ newContactsDict = null;
+ }
+
+ // Open or move user dictionary.
+ final UserBinaryDictionary newUserDictionary;
+ if (!closeUserDictionary && mDictionaries.hasUserDict()) {
+ newUserDictionary = mDictionaries.mUserDictionary;
+ } else {
+ newUserDictionary = new UserBinaryDictionary(context, newLocale);
+ }
+
+ // Open or move user history dictionary.
+ final UserHistoryDictionary newUserHistoryDict;
+ if (!closeUserHistoryDictionary && mDictionaries.hasUserHistoryDict()) {
+ newUserHistoryDict = mDictionaries.mUserHistoryDictionary;
+ } else if (usePersonalizedDicts) {
+ newUserHistoryDict = PersonalizationHelper.getUserHistoryDictionary(context, newLocale);
+ } else {
+ newUserHistoryDict = null;
+ }
+
+ // Open or move personalization dictionary.
+ final PersonalizationDictionary newPersonalizationDict;
+ if (!closePersonalizationDictionary && mDictionaries.hasPersonalizationDict()) {
+ newPersonalizationDict = mDictionaries.mPersonalizationDictionary;
+ } else if (usePersonalizedDicts) {
+ newPersonalizationDict =
+ PersonalizationHelper.getPersonalizationDictionary(context, newLocale);
+ } else {
+ newPersonalizationDict = null;
+ }
+
+ // Replace Dictionaries.
+ final Dictionaries newDictionaries = new Dictionaries(newLocale, newMainDict,
+ newContactsDict, newUserDictionary, newUserHistoryDict, newPersonalizationDict);
+ if (listener != null) {
+ listener.onUpdateMainDictionaryAvailability(newDictionaries.hasMainDict());
+ }
+ final Dictionaries oldDictionaries;
+ synchronized (mLock) {
+ oldDictionaries = mDictionaries;
+ mDictionaries = newDictionaries;
+ if (reloadMainDictionary) {
+ asyncReloadMainDictionary(context, newLocale, listener);
+ }
+ }
+
+ // Clean up old dictionaries.
+ oldDictionaries.mDictMap.clear();
+ if (reloadMainDictionary && oldDictionaries.hasMainDict()) {
+ oldDictionaries.mMainDictionary.close();
+ }
+ if (closeContactsDictionary && oldDictionaries.hasContactsDict()) {
+ oldDictionaries.mContactsDictionary.close();
+ }
+ if (closeUserDictionary && oldDictionaries.hasUserDict()) {
+ oldDictionaries.mUserDictionary.close();
+ }
+ if (closeUserHistoryDictionary && oldDictionaries.hasUserHistoryDict()) {
+ oldDictionaries.mUserHistoryDictionary.close();
+ }
+ if (closePersonalizationDictionary && oldDictionaries.hasPersonalizationDict()) {
+ oldDictionaries.mPersonalizationDictionary.close();
+ }
}
- /**
- * Creates instance for when the settings values have been changed.
- *
- * @param settingsValues the new settings values
- * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null.
- */
- //
- public DictionaryFacilitatorForSuggest(final SettingsValues settingsValues,
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
- mContext = oldDictionaryFacilitator.mContext;
- mLocale = oldDictionaryFacilitator.mLocale;
- mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
- // Transfer main dictionary.
- setMainDictionary(oldDictionaryFacilitator.mMainDictionary);
- oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_MAIN);
- // Transfer user dictionary.
- setUserDictionary(oldDictionaryFacilitator.mUserDictionary);
- oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER);
- // Transfer or create additional dictionaries depending on the settings values.
- resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
+ private void asyncReloadMainDictionary(final Context context, final Locale locale,
+ final DictionaryInitializationListener listener) {
+ final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1);
+ mLatchForWaitingLoadingMainDictionary = latchForWaitingLoadingMainDictionary;
+ ExecutorUtils.getExecutor("InitializeBinaryDictionary").execute(new Runnable() {
+ @Override
+ public void run() {
+ final Dictionary mainDict =
+ DictionaryFactory.createMainDictionaryFromManager(context, locale);
+ synchronized (mLock) {
+ if (locale.equals(mDictionaries.mLocale)) {
+ mDictionaries.setMainDict(mainDict);
+ } else {
+ // Dictionary facilitator has been reset for another locale.
+ mainDict.close();
+ }
+ }
+ if (listener != null) {
+ listener.onUpdateMainDictionaryAvailability(mDictionaries.hasMainDict());
+ }
+ latchForWaitingLoadingMainDictionary.countDown();
+ }
+ });
}
@UsedForTesting
- public DictionaryFacilitatorForSuggest(final Context context, final Locale locale,
+ public void resetDictionariesForTesting(final Context context, final Locale locale,
final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles,
final Map<String, Map<String, String>> additionalDictAttributes) {
- mContext = context;
- mLocale = locale;
- mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
+ Dictionary mainDictionary = null;
+ ContactsBinaryDictionary contactsDictionary = null;
+ UserBinaryDictionary userDictionary = null;
+ UserHistoryDictionary userHistoryDictionary = null;
+ PersonalizationDictionary personalizationDictionary = null;
+
for (final String dictType : dictionaryTypes) {
if (dictType.equals(Dictionary.TYPE_MAIN)) {
- final DictionaryCollection mainDictionary =
- DictionaryFactory.createMainDictionaryFromManager(context, locale);
- setMainDictionary(mainDictionary);
+ mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, locale);
} else if (dictType.equals(Dictionary.TYPE_USER_HISTORY)) {
- final UserHistoryDictionary userHistoryDictionary =
+ userHistoryDictionary =
PersonalizationHelper.getUserHistoryDictionary(context, locale);
// Staring with an empty user history dictionary for testing.
// Testing program may populate this dictionary before actual testing.
userHistoryDictionary.reloadDictionaryIfRequired();
userHistoryDictionary.waitAllTasksForTests();
- setUserHistoryDictionary(userHistoryDictionary);
if (additionalDictAttributes.containsKey(dictType)) {
userHistoryDictionary.clearAndFlushDictionaryWithAdditionalAttributes(
additionalDictAttributes.get(dictType));
}
} else if (dictType.equals(Dictionary.TYPE_PERSONALIZATION)) {
- final PersonalizationDictionary personalizationDictionary =
+ personalizationDictionary =
PersonalizationHelper.getPersonalizationDictionary(context, locale);
// Staring with an empty personalization dictionary for testing.
// Testing program may populate this dictionary before actual testing.
personalizationDictionary.reloadDictionaryIfRequired();
personalizationDictionary.waitAllTasksForTests();
- setPersonalizationDictionary(personalizationDictionary);
if (additionalDictAttributes.containsKey(dictType)) {
personalizationDictionary.clearAndFlushDictionaryWithAdditionalAttributes(
additionalDictAttributes.get(dictType));
}
} else if (dictType.equals(Dictionary.TYPE_USER)) {
final File file = dictionaryFiles.get(dictType);
- final UserBinaryDictionary userDictionary = new UserBinaryDictionary(
- context, locale, file);
+ userDictionary = new UserBinaryDictionary(context, locale, file);
userDictionary.reloadDictionaryIfRequired();
userDictionary.waitAllTasksForTests();
- setUserDictionary(userDictionary);
} else if (dictType.equals(Dictionary.TYPE_CONTACTS)) {
final File file = dictionaryFiles.get(dictType);
- final ContactsBinaryDictionary contactsDictionary = new ContactsBinaryDictionary(
- context, locale, file);
+ contactsDictionary = new ContactsBinaryDictionary(context, locale, file);
contactsDictionary.reloadDictionaryIfRequired();
contactsDictionary.waitAllTasksForTests();
- setContactsDictionary(contactsDictionary);
} else {
throw new RuntimeException("Unknown dictionary type: " + dictType);
}
}
+ mDictionaries = new Dictionaries(locale, mainDictionary, contactsDictionary,
+ userDictionary, userHistoryDictionary, personalizationDictionary);
}
- public boolean needsToBeRecreated(final Locale newLocale,
- final SettingsValues newSettingsValues) {
- return !mLocale.equals(newLocale)
- || (newSettingsValues.mUseContactsDict != (mContactsDictionary != null))
- || (newSettingsValues.mUsePersonalizedDicts != (mUserHistoryDictionary != null))
- || (newSettingsValues.mUsePersonalizedDicts != hasPersonalizationDictionary());
- }
-
- public void close() {
- final HashSet<Dictionary> dictionaries = CollectionUtils.newHashSet();
- dictionaries.addAll(mDictionaries.values());
- for (final Dictionary dictionary : dictionaries) {
- dictionary.close();
+ public void closeDictionaries() {
+ final Dictionaries dictionaries;
+ synchronized (mLock) {
+ dictionaries = mDictionaries;
+ mDictionaries = new Dictionaries();
}
- }
-
- private void loadMainDict(final Context context, final Locale locale,
- final DictionaryInitializationListener listener) {
- mMainDictionary = null;
- if (listener != null) {
- listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
+ if (dictionaries.hasMainDict()) {
+ dictionaries.mMainDictionary.close();
+ }
+ if (dictionaries.hasContactsDict()) {
+ dictionaries.mContactsDictionary.close();
+ }
+ if (dictionaries.hasUserDict()) {
+ dictionaries.mUserDictionary.close();
+ }
+ if (dictionaries.hasUserHistoryDict()) {
+ dictionaries.mUserHistoryDictionary.close();
+ }
+ if (dictionaries.hasPersonalizationDict()) {
+ dictionaries.mPersonalizationDictionary.close();
}
- ExecutorUtils.getExecutor("InitializeBinaryDictionary").execute(new Runnable() {
- public void run() {
- final DictionaryCollection newMainDict =
- DictionaryFactory.createMainDictionaryFromManager(context, locale);
- setMainDictionary(newMainDict);
- if (listener != null) {
- listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
- }
- mLatchForWaitingLoadingMainDictionary.countDown();
- }
- });
}
// The main dictionary could have been loaded asynchronously. Don't cache the return value
// of this method.
- public boolean hasMainDictionary() {
- return null != mMainDictionary && mMainDictionary.isInitialized();
+ public boolean hasInitializedMainDictionary() {
+ final Dictionaries dictionaries = mDictionaries;
+ return dictionaries.hasMainDict() && dictionaries.mMainDictionary.isInitialized();
}
public boolean hasPersonalizationDictionary() {
- return null != mPersonalizationDictionary;
+ return mDictionaries.hasPersonalizationDict();
}
public void flushPersonalizationDictionary() {
- if (hasPersonalizationDictionary()) {
- mPersonalizationDictionary.flush();
+ final PersonalizationDictionary personalizationDict =
+ mDictionaries.mPersonalizationDictionary;
+ if (personalizationDict != null) {
+ personalizationDict.flush();
}
}
@@ -253,177 +369,48 @@ public class DictionaryFacilitatorForSuggest {
public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit)
throws InterruptedException {
waitForLoadingMainDictionary(timeout, unit);
- if (mContactsDictionary != null) {
- mContactsDictionary.waitAllTasksForTests();
+ final Dictionaries dictionaries = mDictionaries;
+ if (dictionaries.hasContactsDict()) {
+ dictionaries.mContactsDictionary.waitAllTasksForTests();
}
- if (mUserDictionary != null) {
- mUserDictionary.waitAllTasksForTests();
+ if (dictionaries.hasUserDict()) {
+ dictionaries.mUserDictionary.waitAllTasksForTests();
}
- if (mUserHistoryDictionary != null) {
- mUserHistoryDictionary.waitAllTasksForTests();
- }
- if (mPersonalizationDictionary != null) {
- mPersonalizationDictionary.waitAllTasksForTests();
- }
- }
-
- private void setMainDictionary(final Dictionary mainDictionary) {
- mMainDictionary = mainDictionary;
- addOrReplaceDictionary(Dictionary.TYPE_MAIN, mainDictionary);
- }
-
- /**
- * 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.
- */
- private void setUserDictionary(final UserBinaryDictionary userDictionary) {
- mUserDictionary = userDictionary;
- addOrReplaceDictionary(Dictionary.TYPE_USER, userDictionary);
- }
-
- /**
- * Sets an optional contacts dictionary resource to be loaded. It is also possible to remove
- * the contacts dictionary by passing null to this method. In this case no contacts dictionary
- * won't be used.
- */
- private void setContactsDictionary(final ContactsBinaryDictionary contactsDictionary) {
- mContactsDictionary = contactsDictionary;
- addOrReplaceDictionary(Dictionary.TYPE_CONTACTS, contactsDictionary);
- }
-
- private void setUserHistoryDictionary(final UserHistoryDictionary userHistoryDictionary) {
- mUserHistoryDictionary = userHistoryDictionary;
- addOrReplaceDictionary(Dictionary.TYPE_USER_HISTORY, userHistoryDictionary);
- }
-
- private void setPersonalizationDictionary(
- final PersonalizationDictionary personalizationDictionary) {
- mPersonalizationDictionary = personalizationDictionary;
- addOrReplaceDictionary(Dictionary.TYPE_PERSONALIZATION, personalizationDictionary);
- }
-
- /**
- * Reset dictionaries that can be turned off according to the user settings.
- *
- * @param oldDictionaryFacilitator the instance having old dictionaries
- * @param settingsValues current SettingsValues
- */
- private void resetAdditionalDictionaries(
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator,
- final SettingsValues settingsValues) {
- // Contacts dictionary
- resetContactsDictionary(null != oldDictionaryFacilitator ?
- oldDictionaryFacilitator.mContactsDictionary : null, settingsValues);
- // User history dictionary & Personalization dictionary
- resetPersonalizedDictionaries(oldDictionaryFacilitator, settingsValues);
- }
-
- /**
- * Set the user history dictionary and personalization dictionary according to the user
- * settings.
- *
- * @param oldDictionaryFacilitator the instance that has been used
- * @param settingsValues current settingsValues
- */
- // TODO: Consolidate resetPersonalizedDictionaries() and resetContactsDictionary(). Call up the
- // new method for each dictionary.
- private void resetPersonalizedDictionaries(
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator,
- final SettingsValues settingsValues) {
- final boolean shouldSetDictionaries = settingsValues.mUsePersonalizedDicts;
-
- final UserHistoryDictionary oldUserHistoryDictionary = (null == oldDictionaryFacilitator) ?
- null : oldDictionaryFacilitator.mUserHistoryDictionary;
- final PersonalizationDictionary oldPersonalizationDictionary =
- (null == oldDictionaryFacilitator) ? null :
- oldDictionaryFacilitator.mPersonalizationDictionary;
- final UserHistoryDictionary userHistoryDictionaryToUse;
- final PersonalizationDictionary personalizationDictionaryToUse;
- if (!shouldSetDictionaries) {
- userHistoryDictionaryToUse = null;
- personalizationDictionaryToUse = null;
- } else {
- if (null != oldUserHistoryDictionary
- && oldUserHistoryDictionary.mLocale.equals(mLocale)) {
- userHistoryDictionaryToUse = oldUserHistoryDictionary;
- } else {
- userHistoryDictionaryToUse =
- PersonalizationHelper.getUserHistoryDictionary(mContext, mLocale);
- }
- if (null != oldPersonalizationDictionary
- && oldPersonalizationDictionary.mLocale.equals(mLocale)) {
- personalizationDictionaryToUse = oldPersonalizationDictionary;
- } else {
- personalizationDictionaryToUse =
- PersonalizationHelper.getPersonalizationDictionary(mContext, mLocale);
- }
+ if (dictionaries.hasUserHistoryDict()) {
+ dictionaries.mUserHistoryDictionary.waitAllTasksForTests();
}
- setUserHistoryDictionary(userHistoryDictionaryToUse);
- setPersonalizationDictionary(personalizationDictionaryToUse);
- }
-
- /**
- * Set the contacts dictionary according to the user settings.
- *
- * This method takes an optional contacts dictionary to use when the locale hasn't changed
- * since the contacts dictionary can be opened or closed as necessary depending on the settings.
- *
- * @param oldContactsDictionary an optional dictionary to use, or null
- * @param settingsValues current settingsValues
- */
- private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary,
- final SettingsValues settingsValues) {
- final boolean shouldSetDictionary = settingsValues.mUseContactsDict;
- final ContactsBinaryDictionary dictionaryToUse;
- if (!shouldSetDictionary) {
- // Make sure the dictionary is closed. If it is already closed, this is a no-op,
- // so it's safe to call it anyways.
- if (null != oldContactsDictionary) oldContactsDictionary.close();
- dictionaryToUse = null;
- } else {
- if (null != oldContactsDictionary) {
- if (!oldContactsDictionary.mLocale.equals(mLocale)) {
- // If the locale has changed then recreate the contacts dictionary. This
- // allows locale dependent rules for handling bigram name predictions.
- oldContactsDictionary.close();
- dictionaryToUse = new ContactsBinaryDictionary(mContext, mLocale);
- } else {
- // Make sure the old contacts dictionary is opened. If it is already open,
- // this is a no-op, so it's safe to call it anyways.
- oldContactsDictionary.reopen(mContext);
- dictionaryToUse = oldContactsDictionary;
- }
- } else {
- dictionaryToUse = new ContactsBinaryDictionary(mContext, mLocale);
- }
+ if (dictionaries.hasPersonalizationDict()) {
+ dictionaries.mPersonalizationDictionary.waitAllTasksForTests();
}
- setContactsDictionary(dictionaryToUse);
}
public boolean isUserDictionaryEnabled() {
- if (mUserDictionary == null) {
+ final UserBinaryDictionary userDictionary = mDictionaries.mUserDictionary;
+ if (userDictionary == null) {
return false;
}
- return mUserDictionary.mEnabled;
+ return userDictionary.mEnabled;
}
public void addWordToUserDictionary(String word) {
- if (mUserDictionary == null) {
+ final UserBinaryDictionary userDictionary = mDictionaries.mUserDictionary;
+ if (userDictionary == null) {
return;
}
- mUserDictionary.addWordToUserDictionary(word);
+ userDictionary.addWordToUserDictionary(word);
}
public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
final String previousWord, final int timeStampInSeconds) {
- if (mUserHistoryDictionary == null) {
+ final Dictionaries dictionaries = mDictionaries;
+ if (!dictionaries.hasUserHistoryDict()) {
return;
}
final int maxFreq = getMaxFrequency(suggestion);
if (maxFreq == 0) {
return;
}
- final String suggestionLowerCase = suggestion.toLowerCase(mLocale);
+ final String suggestionLowerCase = suggestion.toLowerCase(dictionaries.mLocale);
final String secondWord;
if (wasAutoCapitalized) {
secondWord = suggestionLowerCase;
@@ -432,11 +419,11 @@ public class DictionaryFacilitatorForSuggest {
// History dictionary in order to avoid suggesting them until the dictionary
// consolidation is done.
// TODO: Remove this hack when ready.
- final int lowerCasefreqInMainDict = mMainDictionary != null ?
- mMainDictionary.getFrequency(suggestionLowerCase) :
+ final int lowerCaseFreqInMainDict = dictionaries.hasMainDict() ?
+ dictionaries.mMainDictionary.getFrequency(suggestionLowerCase) :
Dictionary.NOT_A_PROBABILITY;
- if (maxFreq < lowerCasefreqInMainDict
- && lowerCasefreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) {
+ if (maxFreq < lowerCaseFreqInMainDict
+ && lowerCaseFreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) {
// Use lower cased word as the word can be a distracter of the popular word.
secondWord = suggestionLowerCase;
} else {
@@ -446,54 +433,56 @@ public class DictionaryFacilitatorForSuggest {
// 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 boolean isValid = maxFreq > 0;
- mUserHistoryDictionary.addToDictionary(
+ dictionaries.mUserHistoryDictionary.addToDictionary(
previousWord, secondWord, isValid, timeStampInSeconds);
}
public void cancelAddingUserHistory(final String previousWord, final String committedWord) {
- if (mUserHistoryDictionary != null) {
- mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord);
+ final UserHistoryDictionary userHistoryDictionary = mDictionaries.mUserHistoryDictionary;
+ if (userHistoryDictionary != null) {
+ userHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord);
}
}
// TODO: Revise the way to fusion suggestion results.
- public void getSuggestions(final WordComposer composer,
+ public SuggestionResults getSuggestionResults(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
- final int sessionId, final Set<SuggestedWordInfo> suggestionSet,
- final ArrayList<SuggestedWordInfo> rawSuggestions) {
- for (final String key : mDictionaries.keySet()) {
- final Dictionary dictionary = mDictionaries.get(key);
+ final int sessionId, final ArrayList<SuggestedWordInfo> rawSuggestions) {
+ final Dictionaries dictionaries = mDictionaries;
+ final Map<String, Dictionary> dictMap = dictionaries.mDictMap;
+ final SuggestionResults suggestionResults =
+ new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS);
+ for (final Dictionary dictionary : dictMap.values()) {
if (null == dictionary) continue;
final ArrayList<SuggestedWordInfo> dictionarySuggestions =
dictionary.getSuggestionsWithSessionId(composer, prevWord, proximityInfo,
blockOffensiveWords, additionalFeaturesOptions, sessionId);
if (null == dictionarySuggestions) continue;
- suggestionSet.addAll(dictionarySuggestions);
+ suggestionResults.addAll(dictionarySuggestions);
if (null != rawSuggestions) {
rawSuggestions.addAll(dictionarySuggestions);
}
}
+ return suggestionResults;
}
public boolean isValidMainDictWord(final String word) {
- if (TextUtils.isEmpty(word) || !hasMainDictionary()) {
+ final Dictionaries dictionaries = mDictionaries;
+ if (TextUtils.isEmpty(word) || !dictionaries.hasMainDict()) {
return false;
}
- return mMainDictionary.isValidWord(word);
+ return dictionaries.mMainDictionary.isValidWord(word);
}
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?
+ final Dictionaries dictionaries = mDictionaries;
+ final String lowerCasedWord = word.toLowerCase(dictionaries.mLocale);
+ final Map<String, Dictionary> dictMap = dictionaries.mDictMap;
+ for (final Dictionary dictionary : dictMap.values()) {
// 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.
@@ -511,9 +500,8 @@ public class DictionaryFacilitatorForSuggest {
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 Map<String, Dictionary> dictMap = mDictionaries.mDictMap;
+ for (final Dictionary dictionary : dictMap.values()) {
final int tempFreq = dictionary.getFrequency(word);
if (tempFreq >= maxFreq) {
maxFreq = tempFreq;
@@ -522,61 +510,50 @@ public class DictionaryFacilitatorForSuggest {
return maxFreq;
}
- private void removeDictionary(final String key) {
- mDictionaries.remove(key);
- }
-
- private void addOrReplaceDictionary(final String key, final Dictionary dict) {
- final Dictionary oldDict;
- if (dict == null) {
- oldDict = mDictionaries.remove(key);
- } else {
- oldDict = mDictionaries.put(key, dict);
- }
- if (oldDict != null && dict != oldDict) {
- oldDict.close();
- }
- }
public void clearUserHistoryDictionary() {
- if (mUserHistoryDictionary == null) {
+ final UserHistoryDictionary userHistoryDict = mDictionaries.mUserHistoryDictionary;
+ if (userHistoryDict == null) {
return;
}
- mUserHistoryDictionary.clearAndFlushDictionary();
+ userHistoryDict.clearAndFlushDictionary();
}
// This method gets called only when the IME receives a notification to remove the
// personalization dictionary.
public void clearPersonalizationDictionary() {
- if (!hasPersonalizationDictionary()) {
+ final PersonalizationDictionary personalizationDict =
+ mDictionaries.mPersonalizationDictionary;
+ if (personalizationDict == null) {
return;
}
- mPersonalizationDictionary.clearAndFlushDictionary();
+ personalizationDict.clearAndFlushDictionary();
}
public void addMultipleDictionaryEntriesToPersonalizationDictionary(
final ArrayList<LanguageModelParam> languageModelParams,
final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) {
- if (!hasPersonalizationDictionary()) {
+ final PersonalizationDictionary personalizationDict =
+ mDictionaries.mPersonalizationDictionary;
+ if (personalizationDict == null) {
if (callback != null) {
callback.onFinished();
}
return;
}
- mPersonalizationDictionary.addMultipleDictionaryEntriesToDictionary(languageModelParams,
- callback);
+ personalizationDict.addMultipleDictionaryEntriesToDictionary(languageModelParams, callback);
}
public void dumpDictionaryForDebug(final String dictName) {
final ExpandableBinaryDictionary dictToDump;
if (dictName.equals(Dictionary.TYPE_CONTACTS)) {
- dictToDump = mContactsDictionary;
+ dictToDump = mDictionaries.mContactsDictionary;
} else if (dictName.equals(Dictionary.TYPE_USER)) {
- dictToDump = mUserDictionary;
+ dictToDump = mDictionaries.mUserDictionary;
} else if (dictName.equals(Dictionary.TYPE_USER_HISTORY)) {
- dictToDump = mUserHistoryDictionary;
+ dictToDump = mDictionaries.mUserHistoryDictionary;
} else if (dictName.equals(Dictionary.TYPE_PERSONALIZATION)) {
- dictToDump = mPersonalizationDictionary;
+ dictToDump = mDictionaries.mPersonalizationDictionary;
} else {
dictToDump = null;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 38e386493..0c0be82df 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -215,7 +215,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
false /* includeResumedWordInSuggestions */);
break;
case MSG_REOPEN_DICTIONARIES:
- latinIme.initSuggest();
+ latinIme.resetSuggest();
// In theory we could call latinIme.updateSuggestionStrip() right away, but
// in the practice, the dictionary is not finished opening yet so we wouldn't
// get any suggestions. Wait one frame.
@@ -478,10 +478,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: Resolve mutual dependencies of {@link #loadSettings()} and {@link #initSuggest()}.
loadSettings();
- initSuggest();
+ resetSuggest();
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.getInstance().init(this, mKeyboardSwitcher);
+ ResearchLogger.getInstance().initDictionary(
+ mInputLogic.mSuggest.mDictionaryFacilitator);
}
// Register to receive ringer mode change and network state change.
@@ -520,31 +522,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// This method is called on startup and language switch, before the new layout has
// been displayed. Opening dictionaries never affects responsivity as dictionaries are
// asynchronously loaded.
- initOrResetSuggestForSettingsValues(mInputLogic.mSuggest, locale, currentSettingsValues);
- }
-
- private void initOrResetSuggestForSettingsValues(final Suggest oldSuggest,
- final Locale locale, final SettingsValues settingsValues) {
- if (!mHandler.hasPendingReopenDictionaries() && oldSuggest != null) {
- // May need to reset dictionaries depending on the user settings.
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
- oldSuggest.mDictionaryFacilitator;
- if (!oldDictionaryFacilitator.needsToBeRecreated(locale, settingsValues)) {
- // Continue to use the same dictionary facilitator if no configuration has changed.
- refreshPersonalizationDictionarySession();
- return;
- }
- final DictionaryFacilitatorForSuggest dictionaryFacilitator =
- new DictionaryFacilitatorForSuggest(settingsValues, oldDictionaryFacilitator);
- // Create Suggest instance with the new dictionary facilitator.
- replaceSuggest(new Suggest(oldSuggest, dictionaryFacilitator));
- } else if (oldSuggest == null) {
- initSuggest();
+ if (!mHandler.hasPendingReopenDictionaries()) {
+ resetSuggestForLocale(locale);
}
+ refreshPersonalizationDictionarySession();
}
private void refreshPersonalizationDictionarySession() {
- final Suggest suggest = mInputLogic.mSuggest;
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ mInputLogic.mSuggest.mDictionaryFacilitator;
final boolean shouldKeepUserHistoryDictionaries;
final boolean shouldKeepPersonalizationDictionaries;
if (mSettings.getCurrent().mUsePersonalizedDicts) {
@@ -559,17 +545,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!shouldKeepUserHistoryDictionaries) {
// Remove user history dictionaries.
PersonalizationHelper.removeAllUserHistoryDictionaries(this);
- if (suggest != null) {
- suggest.mDictionaryFacilitator.clearUserHistoryDictionary();
- }
+ dictionaryFacilitator.clearUserHistoryDictionary();
}
if (!shouldKeepPersonalizationDictionaries) {
// Remove personalization dictionaries.
PersonalizationHelper.removeAllPersonalizationDictionaries(this);
PersonalizationDictionarySessionRegistrar.resetAll(this);
} else {
- final DictionaryFacilitatorForSuggest dictionaryFacilitator =
- (suggest == null) ? null : suggest.mDictionaryFacilitator;
PersonalizationDictionarySessionRegistrar.init(this, dictionaryFacilitator);
}
}
@@ -583,7 +565,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private void initSuggest() {
+ private void resetSuggest() {
final Locale switcherSubtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
final String switcherLocaleStr = switcherSubtypeLocale.toString();
final Locale subtypeLocale;
@@ -599,47 +581,42 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else {
subtypeLocale = switcherSubtypeLocale;
}
- initSuggestForLocale(mInputLogic.mSuggest, subtypeLocale);
+ resetSuggestForLocale(subtypeLocale);
}
- private void initSuggestForLocale(final Suggest oldSuggest, final Locale locale) {
- final SettingsValues settingsValues = mSettings.getCurrent();
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
- (oldSuggest == null) ? null : oldSuggest.mDictionaryFacilitator;
- // Creates new dictionary facilitator for the new locale.
+ /**
+ * Reset suggest by loading dictionaries for the locale and the current settings values.
+ *
+ * @param locale the locale
+ */
+ private void resetSuggestForLocale(final Locale locale) {
final DictionaryFacilitatorForSuggest dictionaryFacilitator =
- new DictionaryFacilitatorForSuggest(this /* context */, locale, settingsValues,
- this /* DictionaryInitializationListener */, oldDictionaryFacilitator);
- final Suggest newSuggest = new Suggest(locale, dictionaryFacilitator);
+ mInputLogic.mSuggest.mDictionaryFacilitator;
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ dictionaryFacilitator.resetDictionaries(this /* context */, locale,
+ settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
+ false /* forceReloadMainDictionary */, this);
if (settingsValues.mCorrectionEnabled) {
- newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold);
+ mInputLogic.mSuggest.setAutoCorrectionThreshold(
+ settingsValues.mAutoCorrectionThreshold);
}
- replaceSuggest(newSuggest);
}
+ /**
+ * Reset suggest by loading the main dictionary of the current locale.
+ */
/* package private */ void resetSuggestMainDict() {
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
- mInputLogic.mSuggest.mDictionaryFacilitator;
final DictionaryFacilitatorForSuggest dictionaryFacilitator =
- new DictionaryFacilitatorForSuggest(this /* listener */, oldDictionaryFacilitator);
- replaceSuggest(new Suggest(mInputLogic.mSuggest /* oldSuggest */, dictionaryFacilitator));
- }
-
- private void replaceSuggest(final Suggest newSuggest) {
- if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.getInstance().initDictionary(newSuggest.mDictionaryFacilitator);
- }
- mInputLogic.replaceSuggest(newSuggest);
- refreshPersonalizationDictionarySession();
+ mInputLogic.mSuggest.mDictionaryFacilitator;
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ dictionaryFacilitator.resetDictionaries(this /* context */,
+ dictionaryFacilitator.getLocale(), settingsValues.mUseContactsDict,
+ settingsValues.mUsePersonalizedDicts, true /* forceReloadMainDictionary */, this);
}
@Override
public void onDestroy() {
- final Suggest suggest = mInputLogic.mSuggest;
- if (suggest != null) {
- suggest.close();
- mInputLogic.mSuggest = null;
- }
+ mInputLogic.mSuggest.mDictionaryFacilitator.closeDictionaries();
mSettings.onDestroy();
unregisterReceiver(mReceiver);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -802,10 +779,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note: the following does a round-trip IPC on the main thread: be careful
final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
- Suggest suggest = mInputLogic.mSuggest;
- if (null != suggest && null != currentLocale && !currentLocale.equals(suggest.mLocale)) {
- initSuggest();
- suggest = mInputLogic.mSuggest;
+ final Suggest suggest = mInputLogic.mSuggest;
+ if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
+ // TODO: Do this automatically.
+ resetSuggest();
}
// TODO[IL]: Can the following be moved to InputLogic#startInput?
@@ -833,13 +810,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (isDifferentTextField ||
!currentSettingsValues.hasSameOrientation(getResources().getConfiguration())) {
loadSettings();
- suggest = mInputLogic.mSuggest;
}
if (isDifferentTextField) {
mainKeyboardView.closing();
currentSettingsValues = mSettings.getCurrent();
- if (suggest != null && currentSettingsValues.mCorrectionEnabled) {
+ if (currentSettingsValues.mCorrectionEnabled) {
suggest.setAutoCorrectionThreshold(currentSettingsValues.mAutoCorrectionThreshold);
}
@@ -865,8 +841,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mHandler.cancelUpdateSuggestionStrip();
- mainKeyboardView.setMainDictionaryAvailability(null != suggest
- ? suggest.mDictionaryFacilitator.hasMainDictionary() : false);
+ mainKeyboardView.setMainDictionaryAvailability(
+ suggest.mDictionaryFacilitator.hasInitializedMainDictionary());
mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn,
currentSettingsValues.mKeyPreviewPopupDismissDelay);
mainKeyboardView.setSlidingKeyInputPreviewEnabled(
@@ -1407,8 +1383,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void getSuggestedWords(final int sessionId, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
- final Suggest suggest = mInputLogic.mSuggest;
- if (keyboard == null || suggest == null) {
+ if (keyboard == null) {
callback.onGetSuggestedWords(SuggestedWords.EMPTY);
return;
}
@@ -1437,7 +1412,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
}
- suggest.getSuggestedWords(mInputLogic.mWordComposer,
+ mInputLogic.mSuggest.getSuggestedWords(mInputLogic.mWordComposer,
mInputLogic.mWordComposer.getPreviousWordForSuggestion(),
keyboard.getProximityInfo(), currentSettings.mBlockPotentiallyOffensive,
currentSettings.mCorrectionEnabled, additionalFeaturesOptions, sessionId,
@@ -1722,12 +1697,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
@UsedForTesting
/* package for test */ void replaceDictionariesForTest(final Locale locale) {
- final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
- mInputLogic.mSuggest.mDictionaryFacilitator;
- final DictionaryFacilitatorForSuggest dictionaryFacilitator =
- new DictionaryFacilitatorForSuggest(this, locale, mSettings.getCurrent(),
- this /* listener */, oldDictionaryFacilitator);
- replaceSuggest(new Suggest(locale, dictionaryFacilitator));
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ mInputLogic.mSuggest.mDictionaryFacilitator.resetDictionaries(this, locale,
+ settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
+ false /* forceReloadMainDictionary */, this /* listener */);
}
// DO NOT USE THIS for any other purpose than testing.
@@ -1738,8 +1711,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
public void dumpDictionaryForDebug(final String dictName) {
- if (mInputLogic.mSuggest == null) {
- initSuggest();
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ mInputLogic.mSuggest.mDictionaryFacilitator;
+ if (dictionaryFacilitator.getLocale() == null) {
+ resetSuggest();
}
mInputLogic.mSuggest.mDictionaryFacilitator.dumpDictionaryForDebug(dictName);
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index ba64028ca..9877dc853 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -23,12 +23,11 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
-import com.android.inputmethod.latin.utils.BoundedTreeSet;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.StringUtils;
+import com.android.inputmethod.latin.utils.SuggestionResults;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.Locale;
/**
@@ -53,29 +52,16 @@ public final class Suggest {
private static final int SUPPRESS_SUGGEST_THRESHOLD = -2000000000;
private static final boolean DBG = LatinImeLogger.sDBG;
- public final DictionaryFacilitatorForSuggest mDictionaryFacilitator;
+ public final DictionaryFacilitatorForSuggest mDictionaryFacilitator =
+ new DictionaryFacilitatorForSuggest();
private float mAutoCorrectionThreshold;
- // Locale used for upper- and title-casing words
- public final Locale mLocale;
-
- // TODO: Move dictionaryFacilitator constructing logics from LatinIME to Suggest.
- public Suggest(final Locale locale,
- final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
- mLocale = locale;
- mDictionaryFacilitator = dictionaryFacilitator;
- }
-
- // Creates instance with new dictionary facilitator.
- public Suggest(final Suggest oldSuggst,
- final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
- mLocale = oldSuggst.mLocale;
- mAutoCorrectionThreshold = oldSuggst.mAutoCorrectionThreshold;
- mDictionaryFacilitator = dictionaryFacilitator;
+ public Locale getLocale() {
+ return mDictionaryFacilitator.getLocale();
}
- public void setAutoCorrectionThreshold(float threshold) {
+ public void setAutoCorrectionThreshold(final float threshold) {
mAutoCorrectionThreshold = threshold;
}
@@ -108,9 +94,6 @@ public final class Suggest {
final int[] additionalFeaturesOptions, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
- final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
- SuggestedWords.MAX_SUGGESTIONS);
-
final String typedWord = wordComposer.getTypedWord();
final String consideredWord = trailingSingleQuotesCount > 0
? typedWord.substring(0, typedWord.length() - trailingSingleQuotesCount)
@@ -132,20 +115,20 @@ public final class Suggest {
} else {
rawSuggestions = null;
}
- mDictionaryFacilitator.getSuggestions(wordComposerForLookup, prevWordForBigram,
- proximityInfo, blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING,
- suggestionsSet, rawSuggestions);
+ final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
+ wordComposerForLookup, prevWordForBigram, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions, SESSION_TYPING, rawSuggestions);
final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
final boolean isAllUpperCase = wordComposer.isAllUpperCase();
final String firstSuggestion;
final String whitelistedWord;
- if (suggestionsSet.isEmpty()) {
+ if (suggestionResults.isEmpty()) {
whitelistedWord = firstSuggestion = null;
} else {
final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo(
- suggestionsSet.first(), mLocale, isAllUpperCase, isFirstCharCapitalized,
- trailingSingleQuotesCount);
+ suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase,
+ isFirstCharCapitalized, trailingSingleQuotesCount);
firstSuggestion = firstSuggestedWordInfo.mWord;
if (SuggestedWordInfo.KIND_WHITELIST != firstSuggestedWordInfo.mKind) {
whitelistedWord = null;
@@ -175,10 +158,10 @@ public final class Suggest {
// the current settings. It may also be useful to know, when the setting is off, whether
// the word *would* have been auto-corrected.
if (!isCorrectionEnabled || !allowsToBeAutoCorrected || isPrediction
- || suggestionsSet.isEmpty() || wordComposer.hasDigits()
+ || suggestionResults.isEmpty() || wordComposer.hasDigits()
|| wordComposer.isMostlyCaps() || wordComposer.isResumed()
- || !mDictionaryFacilitator.hasMainDictionary()
- || SuggestedWordInfo.KIND_SHORTCUT == suggestionsSet.first().mKind) {
+ || !mDictionaryFacilitator.hasInitializedMainDictionary()
+ || SuggestedWordInfo.KIND_SHORTCUT == suggestionResults.first().mKind) {
// If we don't have a main dictionary, we never want to auto-correct. The reason for
// this is, the user may have a contact whose name happens to match a valid word in
// their language, and it will unexpectedly auto-correct. For example, if the user
@@ -190,17 +173,17 @@ public final class Suggest {
hasAutoCorrection = false;
} else {
hasAutoCorrection = AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold(
- suggestionsSet.first(), consideredWord, mAutoCorrectionThreshold);
+ suggestionResults.first(), consideredWord, mAutoCorrectionThreshold);
}
final ArrayList<SuggestedWordInfo> suggestionsContainer =
- CollectionUtils.newArrayList(suggestionsSet);
+ CollectionUtils.newArrayList(suggestionResults);
final int suggestionsCount = suggestionsContainer.size();
if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) {
for (int i = 0; i < suggestionsCount; ++i) {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
- wordInfo, mLocale, isAllUpperCase, isFirstCharCapitalized,
+ wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized,
trailingSingleQuotesCount);
suggestionsContainer.set(i, transformedWordInfo);
}
@@ -244,23 +227,21 @@ public final class Suggest {
final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
final int sessionId, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
- final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
- SuggestedWords.MAX_SUGGESTIONS);
final ArrayList<SuggestedWordInfo> rawSuggestions;
if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) {
rawSuggestions = CollectionUtils.newArrayList();
} else {
rawSuggestions = null;
}
- mDictionaryFacilitator.getSuggestions(wordComposer, prevWordForBigram, proximityInfo,
- blockOffensiveWords, additionalFeaturesOptions, sessionId, suggestionsSet,
- rawSuggestions);
- for (SuggestedWordInfo wordInfo : suggestionsSet) {
+ final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
+ wordComposer, prevWordForBigram, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions, sessionId, rawSuggestions);
+ for (SuggestedWordInfo wordInfo : suggestionResults) {
LatinImeLogger.onAddSuggestedWord(wordInfo.mWord, wordInfo.mSourceDict.mDictType);
}
final ArrayList<SuggestedWordInfo> suggestionsContainer =
- CollectionUtils.newArrayList(suggestionsSet);
+ CollectionUtils.newArrayList(suggestionResults);
final int suggestionsCount = suggestionsContainer.size();
final boolean isFirstCharCapitalized = wordComposer.wasShiftedNoLock();
final boolean isAllUpperCase = wordComposer.isAllUpperCase();
@@ -268,7 +249,7 @@ public final class Suggest {
for (int i = 0; i < suggestionsCount; ++i) {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
- wordInfo, mLocale, isAllUpperCase, isFirstCharCapitalized,
+ wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized,
0 /* trailingSingleQuotesCount */);
suggestionsContainer.set(i, transformedWordInfo);
}
@@ -326,22 +307,6 @@ public final class Suggest {
return suggestionsList;
}
- private static final class SuggestedWordInfoComparator
- implements Comparator<SuggestedWordInfo> {
- // This comparator ranks the word info with the higher frequency first. That's because
- // that's the order we want our elements in.
- @Override
- public int compare(final SuggestedWordInfo o1, final SuggestedWordInfo o2) {
- if (o1.mScore > o2.mScore) return -1;
- if (o1.mScore < o2.mScore) return 1;
- if (o1.mCodePointCount < o2.mCodePointCount) return -1;
- if (o1.mCodePointCount > o2.mCodePointCount) return 1;
- return o1.mWord.compareTo(o2.mWord);
- }
- }
- private static final SuggestedWordInfoComparator sSuggestedWordInfoComparator =
- new SuggestedWordInfoComparator();
-
/* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo(
final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase,
final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) {
@@ -365,8 +330,4 @@ public final class Suggest {
wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord,
wordInfo.mAutoCommitFirstWordConfidence);
}
-
- public void close() {
- mDictionaryFacilitator.close();
- }
}
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 36b30eabe..ffa5e8e89 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -32,6 +32,7 @@ import com.android.inputmethod.event.InputTransaction;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LastComposedWord;
import com.android.inputmethod.latin.LatinIME;
@@ -77,8 +78,7 @@ public final class InputLogic {
private int mSpaceState;
// Never null
public SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
- // TODO: mSuggest should be touched by a single thread.
- public volatile Suggest mSuggest;
+ public final Suggest mSuggest = new Suggest();
public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
public final WordComposer mWordComposer;
@@ -106,15 +106,6 @@ public final class InputLogic {
mInputLogicHandler = InputLogicHandler.NULL_HANDLER;
}
- // Replace the old Suggest with the passed Suggest and close it.
- public void replaceSuggest(final Suggest newSuggest) {
- final Suggest oldSuggest = mSuggest;
- mSuggest = newSuggest;
- if (oldSuggest != null) {
- oldSuggest.close();
- }
- }
-
/**
* Initializes the input logic for input in an editor.
*
@@ -283,23 +274,18 @@ public final class InputLogic {
// We should show the "Touch again to save" hint if the user pressed the first entry
// AND it's in none of our current dictionaries (main, user or otherwise).
- // Please note that if mSuggest is null, it means that everything is off: suggestion
- // and correction, so we shouldn't try to show the hint
- final Suggest suggest = mSuggest;
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ mSuggest.mDictionaryFacilitator;
final boolean showingAddToDictionaryHint =
(SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind
|| SuggestedWordInfo.KIND_OOV_CORRECTION == suggestionInfo.mKind)
- && suggest != null
- // If the suggestion is not in the dictionary, the hint should be shown.
- && !suggest.mDictionaryFacilitator.isValidWord(suggestion,
- true /* ignoreCase */);
+ && !dictionaryFacilitator.isValidWord(suggestion, true /* ignoreCase */);
if (settingsValues.mIsInternal) {
LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
- if (showingAddToDictionaryHint
- && suggest.mDictionaryFacilitator.isUserDictionaryEnabled()) {
+ if (showingAddToDictionaryHint && dictionaryFacilitator.isUserDictionaryEnabled()) {
mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion);
} else {
// If we're not showing the "Touch again to save", then update the suggestion strip.
@@ -1231,20 +1217,17 @@ public final class InputLogic {
if (!settingsValues.mCorrectionEnabled) return;
if (TextUtils.isEmpty(suggestion)) return;
- final Suggest suggest = mSuggest;
- if (suggest == null) return;
-
final boolean wasAutoCapitalized =
mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps();
final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds(
System.currentTimeMillis());
- suggest.mDictionaryFacilitator.addToUserHistory(suggestion, wasAutoCapitalized, prevWord,
+ mSuggest.mDictionaryFacilitator.addToUserHistory(suggestion, wasAutoCapitalized, prevWord,
timeStampInSeconds);
}
public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) {
// Check if we have a suggestion engine attached.
- if (mSuggest == null || !settingsValues.isSuggestionsRequested()) {
+ if (!settingsValues.isSuggestionsRequested()) {
if (mWordComposer.isComposingWord()) {
Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not "
+ "requested!");
@@ -1446,10 +1429,8 @@ public final class InputLogic {
}
mConnection.deleteSurroundingText(deleteLength, 0);
if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) {
- if (mSuggest != null) {
- mSuggest.mDictionaryFacilitator.cancelAddingUserHistory(
- previousWord, committedWordString);
- }
+ mSuggest.mDictionaryFacilitator.cancelAddingUserHistory(
+ previousWord, committedWordString);
}
final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString;
final SpannableString textToCommit = new SpannableString(stringToCommit);
diff --git a/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java b/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java
deleted file mode 100644
index ae1fd3f79..000000000
--- a/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2012 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.utils;
-
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.TreeSet;
-
-/**
- * A TreeSet that is bounded in size and throws everything that's smaller than its limit
- */
-public final class BoundedTreeSet extends TreeSet<SuggestedWordInfo> {
- private final int mCapacity;
- public BoundedTreeSet(final Comparator<SuggestedWordInfo> comparator, final int capacity) {
- super(comparator);
- mCapacity = capacity;
- }
-
- @Override
- public boolean add(final SuggestedWordInfo e) {
- if (size() < mCapacity) return super.add(e);
- if (comparator().compare(e, last()) > 0) return false;
- super.add(e);
- pollLast(); // removes the last element
- return true;
- }
-
- @Override
- public boolean addAll(final Collection<? extends SuggestedWordInfo> e) {
- if (null == e) return false;
- return super.addAll(e);
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
index 562ff9e8d..acd16a9e4 100644
--- a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
+++ b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
@@ -119,7 +119,7 @@ public final class LanguageModelParam {
private static LanguageModelParam detectWhetherVaildWordOrNotAndGetLanguageModelParam(
final String prevWord, final String targetWord, final int timestamp,
final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
- final Locale locale = dictionaryFacilitator.mLocale;
+ final Locale locale = dictionaryFacilitator.getLocale();
if (!dictionaryFacilitator.isValidWord(targetWord, true /* ignoreCase */)) {
// OOV word.
return createAndGetLanguageModelParamOfWord(prevWord, targetWord, timestamp,
diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
new file mode 100644
index 000000000..0b362c48a
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 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.utils;
+
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.TreeSet;
+
+/**
+ * A TreeSet of SuggestedWordInfo that is bounded in size and throws everything that's smaller
+ * than its limit
+ */
+public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
+ public final Locale mLocale;
+ private final int mCapacity;
+
+ public SuggestionResults(final Locale locale, final int capacity) {
+ this(locale, sSuggestedWordInfoComparator, capacity);
+ }
+
+ public SuggestionResults(final Locale locale, final Comparator<SuggestedWordInfo> comparator,
+ final int capacity) {
+ super(comparator);
+ mLocale = locale;
+ mCapacity = capacity;
+ }
+
+ @Override
+ public boolean add(final SuggestedWordInfo e) {
+ if (size() < mCapacity) return super.add(e);
+ if (comparator().compare(e, last()) > 0) return false;
+ super.add(e);
+ pollLast(); // removes the last element
+ return true;
+ }
+
+ @Override
+ public boolean addAll(final Collection<? extends SuggestedWordInfo> e) {
+ if (null == e) return false;
+ return super.addAll(e);
+ }
+
+ private static final class SuggestedWordInfoComparator
+ implements Comparator<SuggestedWordInfo> {
+ // This comparator ranks the word info with the higher frequency first. That's because
+ // that's the order we want our elements in.
+ @Override
+ public int compare(final SuggestedWordInfo o1, final SuggestedWordInfo o2) {
+ if (o1.mScore > o2.mScore) return -1;
+ if (o1.mScore < o2.mScore) return 1;
+ if (o1.mCodePointCount < o2.mCodePointCount) return -1;
+ if (o1.mCodePointCount > o2.mCodePointCount) return 1;
+ return o1.mWord.compareTo(o2.mWord);
+ }
+ }
+
+ private static final SuggestedWordInfoComparator sSuggestedWordInfoComparator =
+ new SuggestedWordInfoComparator();
+}
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 9b1d8c535..ffdb43c15 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -155,8 +155,9 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
}
// Reload the dictionary in case it has changed (e.g., because the user has changed
// languages).
- if ((mDictionaryFacilitator == null || !mDictionaryFacilitator.hasMainDictionary())
- && mDictionaryForTesting == null) {
+ if ((mDictionaryFacilitator == null
+ || !mDictionaryFacilitator.hasInitializedMainDictionary())
+ && mDictionaryForTesting == null) {
// Main dictionary is unavailable. Since we cannot check it, we cannot tell if a
// word is out-of-vocabulary or not. Therefore, we must judge the entire buffer
// contents to potentially pose a privacy risk.