diff options
author | 2014-11-24 13:48:16 -0800 | |
---|---|---|
committer | 2014-12-16 15:56:00 -0800 | |
commit | bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0 (patch) | |
tree | c6b34da6729328cd1cab530c5134135a079f09a8 /java/src/com/android/inputmethod/latin/DictionaryFacilitator.java | |
parent | 2c826fd28eb48bd44e8c3e465f90e99bb22649ac (diff) | |
download | latinime-bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0.tar.gz latinime-bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0.tar.xz latinime-bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0.zip |
Passing account info to dictionaryFacilitator
Attempt to use dictionary facilitor without invoking
preference manager. Instead use account from settings only when
things are being reset/changed. Discussion forked from ag/591663
Overall, the idea here is to maintain an account information
inside dictionary groups. Reset the dictionary groups if
account changes (the way we do for locale). Since only user
history dictionary is currently affected, the check to reset user
history dictionary also includes the check to verify the account.
For other things remain the same.
SettingsValues holds the current account (and is updated if prefs change
due to change in account settings). The updated settings are then
propagated to dictionary facilitator via LatinIME#loadSettings.
Bug:18104749,18469539
Change-Id: I553e776e7ea125d0fb7a1fe70a4c7eb0b2277fb8
Diffstat (limited to 'java/src/com/android/inputmethod/latin/DictionaryFacilitator.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/DictionaryFacilitator.java | 126 |
1 files changed, 89 insertions, 37 deletions
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index acf9cf10c..b8893a5d8 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -44,6 +44,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -56,8 +57,16 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import javax.annotation.Nullable; -// TODO: Consolidate dictionaries in native code. +/** + * Facilitates interaction with different kinds of dictionaries. Provides APIs + * to instantiate and select the correct dictionaries (based on language or account), + * update entries and fetch suggestions. + * + * Currently AndroidSpellCheckerService and LatinIME both use DictionaryFacilitator as + * a client for interacting with dictionaries. + */ public class DictionaryFacilitator { + // TODO: Consolidate dictionaries in native code. public static final String TAG = DictionaryFacilitator.class.getSimpleName(); // HACK: This threshold is being used when adding a capitalized entry in the User History @@ -99,7 +108,7 @@ public class DictionaryFacilitator { private static final String DICT_FACTORY_METHOD_NAME = "getDictionary"; private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES = - new Class[] { Context.class, Locale.class, File.class, String.class }; + new Class[] { Context.class, Locale.class, File.class, String.class, String.class }; private static final String[] SUB_DICT_TYPES = Arrays.copyOfRange(DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS, 1 /* start */, @@ -107,8 +116,8 @@ public class DictionaryFacilitator { /** * Returns whether this facilitator is exactly for this list of locales. + * * @param locales the list of locales to test against - * @return true if this facilitator handles exactly this list of locales, false otherwise */ public boolean isForLocales(final Locale[] locales) { if (locales.length != mDictionaryGroups.length) { @@ -130,33 +139,62 @@ public class DictionaryFacilitator { } /** + * Returns whether this facilitator is exactly for this account. + * + * @param account the account to test against. + */ + public boolean isForAccount(@Nullable final String account) { + for (final DictionaryGroup group : mDictionaryGroups) { + if (!TextUtils.equals(group.mAccount, account)) { + return false; + } + } + return true; + } + + /** * A group of dictionaries that work together for a single language. */ private static class DictionaryGroup { + // TODO: Add null analysis annotations. // TODO: Run evaluation to determine a reasonable value for these constants. The current // values are ad-hoc and chosen without any particular care or methodology. public static final float WEIGHT_FOR_MOST_PROBABLE_LANGUAGE = 1.0f; public static final float WEIGHT_FOR_GESTURING_IN_NOT_MOST_PROBABLE_LANGUAGE = 0.95f; public static final float WEIGHT_FOR_TYPING_IN_NOT_MOST_PROBABLE_LANGUAGE = 0.6f; - public final Locale mLocale; - private Dictionary mMainDict; + /** + * The locale associated with the dictionary group. + */ + @Nullable public final Locale mLocale; + + /** + * The user account associated with the dictionary group. + */ + @Nullable public final String mAccount; + + @Nullable private Dictionary mMainDict; // Confidence that the most probable language is actually the language the user is // typing in. For now, this is simply the number of times a word from this language // has been committed in a row. private int mConfidence = 0; + public float mWeightForTypingInLocale = WEIGHT_FOR_MOST_PROBABLE_LANGUAGE; public float mWeightForGesturingInLocale = WEIGHT_FOR_MOST_PROBABLE_LANGUAGE; public final ConcurrentHashMap<String, ExpandableBinaryDictionary> mSubDictMap = new ConcurrentHashMap<>(); public DictionaryGroup() { - mLocale = null; + this(null /* locale */, null /* mainDict */, null /* account */, + Collections.<String, ExpandableBinaryDictionary>emptyMap() /* subDicts */); } - public DictionaryGroup(final Locale locale, final Dictionary mainDict, + public DictionaryGroup(@Nullable final Locale locale, + @Nullable final Dictionary mainDict, + @Nullable final String account, final Map<String, ExpandableBinaryDictionary> subDicts) { mLocale = locale; + mAccount = account; // The main dictionary can be asynchronously loaded. setMainDict(mainDict); for (final Map.Entry<String, ExpandableBinaryDictionary> entry : subDicts.entrySet()) { @@ -190,10 +228,17 @@ public class DictionaryFacilitator { return mSubDictMap.get(dictType); } - public boolean hasDict(final String dictType) { + public boolean hasDict(final String dictType, @Nullable final String account) { if (Dictionary.TYPE_MAIN.equals(dictType)) { return mMainDict != null; } + if (Dictionary.TYPE_USER_HISTORY.equals(dictType) && + !TextUtils.equals(account, mAccount)) { + // If the dictionary type is user history, & if the account doesn't match, + // return immediately. If the account matches, continue looking it up in the + // sub dictionary map. + return false; + } return mSubDictMap.containsKey(dictType); } @@ -310,7 +355,7 @@ public class DictionaryFacilitator { @Nullable private static ExpandableBinaryDictionary getSubDict(final String dictType, final Context context, final Locale locale, final File dictFile, - final String dictNamePrefix) { + final String dictNamePrefix, @Nullable final String account) { final Class<? extends ExpandableBinaryDictionary> dictClass = DICT_TYPE_TO_CLASS.get(dictType); if (dictClass == null) { @@ -320,7 +365,7 @@ public class DictionaryFacilitator { final Method factoryMethod = dictClass.getMethod(DICT_FACTORY_METHOD_NAME, DICT_FACTORY_METHOD_ARG_TYPES); final Object dict = factoryMethod.invoke(null /* obj */, - new Object[] { context, locale, dictFile, dictNamePrefix }); + new Object[] { context, locale, dictFile, dictNamePrefix, account }); return (ExpandableBinaryDictionary) dict; } catch (final NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { @@ -332,17 +377,19 @@ public class DictionaryFacilitator { public void resetDictionaries(final Context context, final Locale[] newLocales, final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, + @Nullable final String account, final DictionaryInitializationListener listener) { resetDictionariesWithDictNamePrefix(context, newLocales, useContactsDict, - usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */); + usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */, + account); } @Nullable static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups, final Locale locale) { - for (int i = 0; i < dictionaryGroups.length; ++i) { - if (locale.equals(dictionaryGroups[i].mLocale)) { - return dictionaryGroups[i]; + for (DictionaryGroup dictionaryGroup : dictionaryGroups) { + if (locale.equals(dictionaryGroup.mLocale)) { + return dictionaryGroup; } } return null; @@ -350,11 +397,13 @@ public class DictionaryFacilitator { public void resetDictionariesWithDictNamePrefix(final Context context, final Locale[] newLocales, - final boolean useContactsDict, final boolean usePersonalizedDicts, + final boolean useContactsDict, + final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, @Nullable final DictionaryInitializationListener listener, - final String dictNamePrefix) { - final HashMap<Locale, ArrayList<String>> existingDictsToCleanup = new HashMap<>(); + final String dictNamePrefix, + @Nullable final String account) { + final HashMap<Locale, ArrayList<String>> existingDictionariesToCleanup = new HashMap<>(); // TODO: Make subDictTypesToUse configurable by resource or a static final list. final HashSet<String> subDictTypesToUse = new HashSet<>(); subDictTypesToUse.add(Dictionary.TYPE_USER); @@ -369,20 +418,20 @@ public class DictionaryFacilitator { // Gather all dictionaries. We'll remove them from the list to clean up later. for (final Locale newLocale : newLocales) { - final ArrayList<String> dictsForLocale = new ArrayList<>(); - existingDictsToCleanup.put(newLocale, dictsForLocale); + final ArrayList<String> dictTypeForLocale = new ArrayList<>(); + existingDictionariesToCleanup.put(newLocale, dictTypeForLocale); final DictionaryGroup currentDictionaryGroupForLocale = findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); if (null == currentDictionaryGroupForLocale) { continue; } for (final String dictType : SUB_DICT_TYPES) { - if (currentDictionaryGroupForLocale.hasDict(dictType)) { - dictsForLocale.add(dictType); + if (currentDictionaryGroupForLocale.hasDict(dictType, account)) { + dictTypeForLocale.add(dictType); } } - if (currentDictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN)) { - dictsForLocale.add(Dictionary.TYPE_MAIN); + if (currentDictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { + dictTypeForLocale.add(Dictionary.TYPE_MAIN); } } @@ -391,34 +440,35 @@ public class DictionaryFacilitator { final Locale newLocale = newLocales[i]; final DictionaryGroup dictionaryGroupForLocale = findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); - final ArrayList<String> dictsToCleanupForLocale = existingDictsToCleanup.get(newLocale); + final ArrayList<String> dictTypesToCleanupForLocale = + existingDictionariesToCleanup.get(newLocale); final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale); final Dictionary mainDict; if (forceReloadMainDictionary || noExistingDictsForThisLocale - || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN)) { + || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { mainDict = null; } else { mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN); - dictsToCleanupForLocale.remove(Dictionary.TYPE_MAIN); + dictTypesToCleanupForLocale.remove(Dictionary.TYPE_MAIN); } final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>(); for (final String subDictType : subDictTypesToUse) { final ExpandableBinaryDictionary subDict; if (noExistingDictsForThisLocale - || !dictionaryGroupForLocale.hasDict(subDictType)) { + || !dictionaryGroupForLocale.hasDict(subDictType, account)) { // Create a new dictionary. subDict = getSubDict(subDictType, context, newLocale, null /* dictFile */, - dictNamePrefix); + dictNamePrefix, account); } else { // Reuse the existing dictionary, and don't close it at the end subDict = dictionaryGroupForLocale.getSubDict(subDictType); - dictsToCleanupForLocale.remove(subDictType); + dictTypesToCleanupForLocale.remove(subDictType); } subDicts.put(subDictType, subDict); } - newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, subDicts); + newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, account, subDicts); } // Replace Dictionaries. @@ -437,9 +487,9 @@ public class DictionaryFacilitator { } // Clean up old dictionaries. - for (final Locale localeToCleanUp : existingDictsToCleanup.keySet()) { + for (final Locale localeToCleanUp : existingDictionariesToCleanup.keySet()) { final ArrayList<String> dictTypesToCleanUp = - existingDictsToCleanup.get(localeToCleanUp); + existingDictionariesToCleanup.get(localeToCleanUp); final DictionaryGroup dictionarySetToCleanup = findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp); for (final String dictType : dictTypesToCleanUp) { @@ -493,7 +543,8 @@ public class DictionaryFacilitator { @UsedForTesting public void resetDictionariesForTesting(final Context context, final Locale[] locales, final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, - final Map<String, Map<String, String>> additionalDictAttributes) { + final Map<String, Map<String, String>> additionalDictAttributes, + @Nullable final String account) { Dictionary mainDictionary = null; final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>(); @@ -507,7 +558,7 @@ public class DictionaryFacilitator { } else { final File dictFile = dictionaryFiles.get(dictType); final ExpandableBinaryDictionary dict = getSubDict( - dictType, context, locale, dictFile, "" /* dictNamePrefix */); + dictType, context, locale, dictFile, "" /* dictNamePrefix */, account); if (additionalDictAttributes.containsKey(dictType)) { dict.clearAndFlushDictionaryWithAdditionalAttributes( additionalDictAttributes.get(dictType)); @@ -520,7 +571,7 @@ public class DictionaryFacilitator { subDicts.put(dictType, dict); } } - dictionaryGroups[i] = new DictionaryGroup(locale, mainDictionary, subDicts); + dictionaryGroups[i] = new DictionaryGroup(locale, mainDictionary, account, subDicts); } mDictionaryGroups = dictionaryGroups; mMostProbableDictionaryGroup = dictionaryGroups[0]; @@ -576,7 +627,7 @@ public class DictionaryFacilitator { public boolean hasPersonalizationDictionary() { final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION)) { + if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION, null /* account */)) { return true; } } @@ -677,7 +728,8 @@ public class DictionaryFacilitator { // History dictionary in order to avoid suggesting them until the dictionary // consolidation is done. // TODO: Remove this hack when ready. - final int lowerCaseFreqInMainDict = dictionaryGroup.hasDict(Dictionary.TYPE_MAIN) ? + final int lowerCaseFreqInMainDict = dictionaryGroup.hasDict(Dictionary.TYPE_MAIN, + null /* account */) ? dictionaryGroup.getDict(Dictionary.TYPE_MAIN).getFrequency(lowerCasedWord) : Dictionary.NOT_A_PROBABILITY; if (maxFreq < lowerCaseFreqInMainDict |