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
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 59763c0..22fd907 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -39,6 +39,8 @@
import java.util.List;
import java.util.Locale;
+import javax.annotation.Nullable;
+
public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME};
@@ -86,7 +88,7 @@
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
@ExternallyReferenced
public static ContactsBinaryDictionary getDictionary(final Context context, final Locale locale,
- final File dictFile, final String dictNamePrefix) {
+ final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return new ContactsBinaryDictionary(context, locale, dictFile, dictNamePrefix + NAME);
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index acf9cf1..b8893a5 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.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 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 @@
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 @@
/**
* 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 @@
}
/**
+ * 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 @@
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 @@
@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 @@
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 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 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 @@
// 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 @@
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 @@
}
// 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 @@
@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 @@
} 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 @@
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 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 @@
// 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
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
index b578159..3119ff8 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
@@ -102,10 +102,12 @@
private void resetDictionariesForLocaleLocked(final DictionaryFacilitator dictionaryFacilitator,
final Locale locale) {
+ // Note: Given that personalized dictionaries are not used here; we can pass null account.
dictionaryFacilitator.resetDictionariesWithDictNamePrefix(mContext, new Locale[] { locale },
mUseContactsDictionary, false /* usePersonalizedDicts */,
false /* forceReloadMainDictionary */, null /* listener */,
- mDictionaryNamePrefix);
+ mDictionaryNamePrefix,
+ null /* account */);
}
public void setUseContactsDictionary(final boolean useContectsDictionary) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d6ec57f..1525a92 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -633,12 +633,13 @@
// been displayed. Opening dictionaries never affects responsivity as dictionaries are
// asynchronously loaded.
if (!mHandler.hasPendingReopenDictionaries()) {
- resetDictionaryFacilitatorForLocale(locales);
+ resetDictionaryFacilitator(locales);
}
mDictionaryFacilitator.updateEnabledSubtypes(mRichImm.getMyEnabledInputMethodSubtypeList(
true /* allowsImplicitlySelectedSubtypes */));
refreshPersonalizationDictionarySession(currentSettingsValues);
mStatsUtilsManager.onLoadSettings(currentSettingsValues);
+ resetDictionaryFacilitatorIfNecessary();
}
private void refreshPersonalizationDictionarySession(
@@ -676,7 +677,8 @@
void resetDictionaryFacilitatorIfNecessary() {
final Locale[] subtypeSwitcherLocales = mRichImm.getCurrentSubtypeLocales();
- if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales)) {
+ if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales)
+ && mDictionaryFacilitator.isForAccount(mSettings.getCurrent().mAccount)) {
return;
}
final Locale[] subtypeLocales;
@@ -690,20 +692,23 @@
} else {
subtypeLocales = subtypeSwitcherLocales;
}
- resetDictionaryFacilitatorForLocale(subtypeLocales);
+ resetDictionaryFacilitator(subtypeLocales);
}
/**
- * Reset the facilitator by loading dictionaries for the locales and the current settings values
+ * Reset the facilitator by loading dictionaries for the locales and
+ * the current settings values.
*
* @param locales the locales
*/
- // TODO: make sure the current settings always have the right locales, and read from them
- private void resetDictionaryFacilitatorForLocale(final Locale[] locales) {
+ // TODO: make sure the current settings always have the right locales, and read from them.
+ private void resetDictionaryFacilitator(final Locale[] locales) {
final SettingsValues settingsValues = mSettings.getCurrent();
mDictionaryFacilitator.resetDictionaries(this /* context */, locales,
settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
- false /* forceReloadMainDictionary */, this);
+ false /* forceReloadMainDictionary */,
+ settingsValues.mAccount,
+ this /* DictionaryInitializationListener */);
if (settingsValues.mAutoCorrectionEnabledPerUserSettings) {
mInputLogic.mSuggest.setAutoCorrectionThreshold(
settingsValues.mAutoCorrectionThreshold);
@@ -718,7 +723,10 @@
final SettingsValues settingsValues = mSettings.getCurrent();
mDictionaryFacilitator.resetDictionaries(this /* context */,
mDictionaryFacilitator.getLocales(), settingsValues.mUseContactsDict,
- settingsValues.mUsePersonalizedDicts, true /* forceReloadMainDictionary */, this);
+ settingsValues.mUsePersonalizedDicts,
+ true /* forceReloadMainDictionary */,
+ settingsValues.mAccount,
+ this /* DictionaryInitializationListener */);
}
@Override
@@ -1934,7 +1942,9 @@
final SettingsValues settingsValues = mSettings.getCurrent();
mDictionaryFacilitator.resetDictionaries(this, new Locale[] { locale },
settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
- false /* forceReloadMainDictionary */, this /* listener */);
+ false /* forceReloadMainDictionary */,
+ settingsValues.mAccount,
+ this /* DictionaryInitializationListener */);
}
// DO NOT USE THIS for any other purpose than testing.
diff --git a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
index 2dbab0a..8926c06 100644
--- a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
@@ -114,7 +114,7 @@
return personalizationDict;
}
personalizationDict = PersonalizationDictionary.getDictionary(context, locale,
- null /* dictFile */, "" /* dictNamePrefix */);
+ null /* dictFile */, "" /* dictNamePrefix */, null /* account */);
mPersonalizationDictsToUpdate.put(locale, personalizationDict);
return personalizationDict;
}
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index 2b7fb17..2d2b3d0 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -36,6 +36,8 @@
import java.util.Arrays;
import java.util.Locale;
+import javax.annotation.Nullable;
+
/**
* An expandable dictionary that stores the words in the user dictionary provider into a binary
* dictionary file to use it from native code.
@@ -104,7 +106,7 @@
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
@ExternallyReferenced
public static UserBinaryDictionary getDictionary(final Context context, final Locale locale,
- final File dictFile, final String dictNamePrefix) {
+ final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return new UserBinaryDictionary(context, locale, false /* alsoUseMoreRestrictiveLocales */,
dictFile, dictNamePrefix + NAME);
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
index 39d9596..f663fe9 100644
--- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
@@ -25,6 +25,8 @@
import java.io.File;
import java.util.Locale;
+import javax.annotation.Nullable;
+
public class ContextualDictionary extends ExpandableBinaryDictionary {
/* package */ static final String NAME = ContextualDictionary.class.getSimpleName();
@@ -40,7 +42,7 @@
@SuppressWarnings("unused")
@ExternallyReferenced
public static ContextualDictionary getDictionary(final Context context, final Locale locale,
- final File dictFile, final String dictNamePrefix) {
+ final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return new ContextualDictionary(context, locale, dictFile);
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
index 33d1273..76451cc 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
@@ -24,6 +24,8 @@
import java.io.File;
import java.util.Locale;
+import javax.annotation.Nullable;
+
public class PersonalizationDictionary extends DecayingExpandableBinaryDictionaryBase {
/* package */ static final String NAME = PersonalizationDictionary.class.getSimpleName();
@@ -37,7 +39,8 @@
@SuppressWarnings("unused")
@ExternallyReferenced
public static PersonalizationDictionary getDictionary(final Context context,
- final Locale locale, final File dictFile, final String dictNamePrefix) {
+ final Locale locale, final File dictFile, final String dictNamePrefix,
+ @Nullable final String account) {
return PersonalizationHelper.getPersonalizationDictionary(context, locale);
}
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
index b595f39..4231450 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -64,7 +64,8 @@
return dict;
}
}
- final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale);
+ final UserHistoryDictionary dict = new UserHistoryDictionary(
+ context, locale, accountName);
sLangUserHistoryDictCache.put(lookupStr, new SoftReference<>(dict));
return dict;
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
index 946835c..2e41027 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -37,20 +37,18 @@
import javax.annotation.Nullable;
/**
- * Locally gathers stats about the words user types and various other signals like auto-correction
- * cancellation or manual picks. This allows the keyboard to adapt to the typist over time.
+ * Locally gathers statistics about the words user types and various other signals like
+ * auto-correction cancellation or manual picks. This allows the keyboard to adapt to the
+ * typist over time.
*/
public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase {
static final String NAME = UserHistoryDictionary.class.getSimpleName();
// TODO: Make this constructor private
- UserHistoryDictionary(final Context context, final Locale locale) {
+ UserHistoryDictionary(final Context context, final Locale locale,
+ @Nullable final String account) {
super(context,
- getUserHistoryDictName(
- NAME,
- locale,
- null /* dictFile */,
- context),
+ getUserHistoryDictName(NAME, locale, null /* dictFile */, account),
locale,
Dictionary.TYPE_USER_HISTORY,
null /* dictFile */);
@@ -61,24 +59,21 @@
*/
@UsedForTesting
static String getUserHistoryDictName(final String name, final Locale locale,
- @Nullable final File dictFile, final Context context) {
+ @Nullable final File dictFile, @Nullable final String account) {
if (!ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) {
return getDictName(name, locale, dictFile);
}
- return getUserHistoryDictNamePerAccount(name, locale, dictFile, context);
+ return getUserHistoryDictNamePerAccount(name, locale, dictFile, account);
}
/**
* Uses the currently signed in account to determine the dictionary name.
*/
private static String getUserHistoryDictNamePerAccount(final String name, final Locale locale,
- @Nullable final File dictFile, final Context context) {
+ @Nullable final File dictFile, @Nullable final String account) {
if (dictFile != null) {
return dictFile.getName();
}
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- final String account = prefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME,
- null /* default */);
String dictName = name + "." + locale.toString();
if (account != null) {
dictName += "." + account;
@@ -90,14 +85,7 @@
@SuppressWarnings("unused")
@ExternallyReferenced
public static UserHistoryDictionary getDictionary(final Context context, final Locale locale,
- final File dictFile, final String dictNamePrefix) {
- final String account;
- if (ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) {
- account = PreferenceManager.getDefaultSharedPreferences(context)
- .getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null /* default */);
- } else {
- account = null;
- }
+ final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return PersonalizationHelper.getUserHistoryDictionary(context, locale, account);
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 5f1a7af..0669026 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -36,6 +36,7 @@
import java.util.Locale;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
* When you call the constructor of this class, you may want to change the current system locale by
@@ -120,6 +121,8 @@
public final float mKeyPreviewDismissEndXScale;
public final float mKeyPreviewDismissEndYScale;
+ @Nullable public final String mAccount;
+
public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res,
@Nonnull final InputAttributes inputAttributes) {
mLocale = res.getConfiguration().locale;
@@ -176,6 +179,8 @@
mPlausibilityThreshold = Settings.readPlausibilityThreshold(res);
mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res);
mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true);
+ mAccount = prefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME,
+ null /* default */);
mGestureFloatingPreviewTextEnabled = !mInputAttributes.mDisableGestureFloatingPreviewText
&& prefs.getBoolean(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true);
mPhraseGestureEnabled = Settings.readPhraseGestureEnabled(prefs, res);
diff --git a/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java
index f07dac7..9d211c9 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java
@@ -18,6 +18,7 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -42,7 +43,7 @@
final DictionaryFacilitator dictionaryFacilitator = new DictionaryFacilitator();
dictionaryFacilitator.resetDictionariesForTesting(getContext(),
new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(),
- new HashMap<String, Map<String, String>>());
+ Collections.<String, Map<String, String>>emptyMap(), null /* account */);
return dictionaryFacilitator;
}
diff --git a/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java
index dc6fb00..b133d61 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java
@@ -18,6 +18,7 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -57,7 +58,7 @@
final DictionaryFacilitator dictionaryFacilitator = new DictionaryFacilitator(getContext());
dictionaryFacilitator.resetDictionariesForTesting(getContext(),
new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(),
- new HashMap<String, Map<String, String>>());
+ Collections.<String, Map<String, String>>emptyMap(), null /* account */);
// Set subtypes.
RichInputMethodManager.init(getContext());
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index d83c4a5..6dddc97 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -16,8 +16,6 @@
package com.android.inputmethod.latin.personalization;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -25,7 +23,6 @@
import com.android.inputmethod.latin.ExpandableBinaryDictionary;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.NgramContext.WordInfo;
-import com.android.inputmethod.latin.settings.LocalSettingsConstants;
import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
import com.android.inputmethod.latin.utils.DistracterFilter;
@@ -35,8 +32,6 @@
import java.util.Random;
import java.util.concurrent.TimeUnit;
-import javax.annotation.Nullable;
-
/**
* Unit tests for UserHistoryDictionary
*/
@@ -48,9 +43,6 @@
private int mCurrentTime = 0;
- private SharedPreferences mPrefs;
- private String mLastKnownAccount = null;
-
private static void printAllFiles(final File dir) {
Log.d(TAG, dir.getAbsolutePath());
for (final File file : dir.listFiles()) {
@@ -78,12 +70,6 @@
@Override
protected void setUp() throws Exception {
super.setUp();
-
- mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
- // Keep track of the current account so that we restore it when the test finishes.
- mLastKnownAccount = mPrefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null);
- updateAccountName(TEST_ACCOUNT);
-
resetCurrentTimeForTestMode();
UserHistoryDictionaryTestsHelper.removeAllTestDictFiles(
UserHistoryDictionaryTestsHelper.TEST_LOCALE_PREFIX, mContext);
@@ -94,10 +80,6 @@
UserHistoryDictionaryTestsHelper.removeAllTestDictFiles(
UserHistoryDictionaryTestsHelper.TEST_LOCALE_PREFIX, mContext);
stopTestModeInNativeCode();
-
- // Restore the account that was present before running the test.
- updateAccountName(mLastKnownAccount);
-
super.tearDown();
}
@@ -106,14 +88,6 @@
setCurrentTimeForTestMode(mCurrentTime);
}
- private void updateAccountName(@Nullable final String accountName) {
- if (accountName == null) {
- mPrefs.edit().remove(LocalSettingsConstants.PREF_ACCOUNT_NAME).apply();
- } else {
- mPrefs.edit().putString(LocalSettingsConstants.PREF_ACCOUNT_NAME, accountName).apply();
- }
- }
-
private void forcePassingShortTime() {
// 3 days.
final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(3);
@@ -147,17 +121,20 @@
dict.waitAllTasksForTests();
}
- public void testRandomWords() {
+ private void doTestRandomWords(final String testAccount) {
Log.d(TAG, "This test can be used for profiling.");
Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
final Locale dummyLocale = UserHistoryDictionaryTestsHelper.getDummyLocale("random_words");
final String dictName = UserHistoryDictionary.getUserHistoryDictName(
- UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
+ UserHistoryDictionary.NAME, dummyLocale,
+ null /* dictFile */,
+ testAccount /* account */);
final File dictFile = ExpandableBinaryDictionary.getDictFile(
mContext, dictName, null /* dictFile */);
final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
- getContext(), dummyLocale, TEST_ACCOUNT);
+ getContext(), dummyLocale, testAccount);
clearHistory(dict);
+
final int numberOfWords = 1000;
final Random random = new Random(123456);
assertTrue(UserHistoryDictionaryTestsHelper.addAndWriteRandomWords(
@@ -165,7 +142,23 @@
assertDictionaryExists(dict, dictFile);
}
+ public void testRandomWords_NullAccount() {
+ doTestRandomWords(null /* testAccount */);
+ }
+
+ public void testRandomWords() {
+ doTestRandomWords(TEST_ACCOUNT);
+ }
+
public void testStressTestForSwitchingLanguagesAndAddingWords() {
+ doTestStressTestForSwitchingLanguagesAndAddingWords(TEST_ACCOUNT);
+ }
+
+ public void testStressTestForSwitchingLanguagesAndAddingWords_NullAccount() {
+ doTestStressTestForSwitchingLanguagesAndAddingWords(null /* testAccount */);
+ }
+
+ private void doTestStressTestForSwitchingLanguagesAndAddingWords(final String testAccount) {
final int numberOfLanguages = 2;
final int numberOfLanguageSwitching = 80;
final int numberOfWordsInsertedForEachLanguageSwitch = 100;
@@ -181,11 +174,12 @@
final Locale dummyLocale =
UserHistoryDictionaryTestsHelper.getDummyLocale("switching_languages" + i);
final String dictName = UserHistoryDictionary.getUserHistoryDictName(
- UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
+ UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */,
+ testAccount /* account */);
dictFiles[i] = ExpandableBinaryDictionary.getDictFile(
mContext, dictName, null /* dictFile */);
dicts[i] = PersonalizationHelper.getUserHistoryDictionary(getContext(),
- dummyLocale, TEST_ACCOUNT);
+ dummyLocale, testAccount);
clearHistory(dicts[i]);
}
@@ -212,16 +206,24 @@
}
public void testAddManyWords() {
+ doTestAddManyWords(TEST_ACCOUNT);
+ }
+
+ public void testAddManyWords_NullAccount() {
+ doTestAddManyWords(null /* testAccount */);
+ }
+
+ private void doTestAddManyWords(final String testAccount) {
final Locale dummyLocale =
UserHistoryDictionaryTestsHelper.getDummyLocale("many_random_words");
final String dictName = UserHistoryDictionary.getUserHistoryDictName(
- UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
+ UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, testAccount);
final File dictFile = ExpandableBinaryDictionary.getDictFile(
mContext, dictName, null /* dictFile */);
final int numberOfWords = 10000;
final Random random = new Random(123456);
final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
- getContext(), dummyLocale, TEST_ACCOUNT);
+ getContext(), dummyLocale, testAccount);
clearHistory(dict);
assertTrue(UserHistoryDictionaryTestsHelper.addAndWriteRandomWords(dict,
numberOfWords, random, true /* checksContents */, mCurrentTime));
@@ -229,9 +231,17 @@
}
public void testDecaying() {
+ doTestDecaying(TEST_ACCOUNT);
+ }
+
+ public void testDecaying_NullAccount() {
+ doTestDecaying(null /* testAccount */);
+ }
+
+ private void doTestDecaying(final String testAccount) {
final Locale dummyLocale = UserHistoryDictionaryTestsHelper.getDummyLocale("decaying");
final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
- getContext(), dummyLocale, TEST_ACCOUNT);
+ getContext(), dummyLocale, testAccount);
resetCurrentTimeForTestMode();
clearHistory(dict);
dict.waitAllTasksForTests();
@@ -262,9 +272,4 @@
assertFalse(dict.isInDictionary(word));
}
}
-
- public void testRandomWords_NullAccount() {
- updateAccountName(null);
- testRandomWords();
- }
}
\ No newline at end of file