[ML5] Rewrite resetDictionariesWithDictNamePrefix

This change rewrites resetDictionariesWithDictNamePrefix so
that it would work if there were several locales, which is going to
happen shortly. This change on its own is quite large and difficult
already, so I didn't want to merge it into the change that actually
makes several locales happen; another such change is following.

Change-Id: Ibb80b05b73c0f0f0bea64b7e308cc4d38ca448f9
main
Jean Chalard 2014-09-02 16:35:36 +09:00
parent eff9be9cd6
commit e6df5f015c
2 changed files with 80 additions and 51 deletions

View File

@ -67,7 +67,7 @@ public class DictionaryFacilitator {
// To synchronize assigning mDictionaryGroup to ensure closing dictionaries. // To synchronize assigning mDictionaryGroup to ensure closing dictionaries.
private final Object mLock = new Object(); private final Object mLock = new Object();
private final DistracterFilter mDistracterFilter; private final DistracterFilter mDistracterFilter;
private final PersonalizationDictionaryFacilitator mPersonalizationDictionaryFacilitator; private final PersonalizationHelperForDictionaryFacilitator mPersonalizationHelper;
private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS = private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS =
new String[] { new String[] {
@ -175,22 +175,22 @@ public class DictionaryFacilitator {
public DictionaryFacilitator() { public DictionaryFacilitator() {
mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER; mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER;
mPersonalizationDictionaryFacilitator = null; mPersonalizationHelper = null;
} }
public DictionaryFacilitator(final Context context) { public DictionaryFacilitator(final Context context) {
mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context); mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context);
mPersonalizationDictionaryFacilitator = mPersonalizationHelper =
new PersonalizationDictionaryFacilitator(context, mDistracterFilter); new PersonalizationHelperForDictionaryFacilitator(context, mDistracterFilter);
} }
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) { public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
mDistracterFilter.updateEnabledSubtypes(enabledSubtypes); mDistracterFilter.updateEnabledSubtypes(enabledSubtypes);
mPersonalizationDictionaryFacilitator.updateEnabledSubtypes(enabledSubtypes); mPersonalizationHelper.updateEnabledSubtypes(enabledSubtypes);
} }
public void setIsMonolingualUser(final boolean isMonolingualUser) { public void setIsMonolingualUser(final boolean isMonolingualUser) {
mPersonalizationDictionaryFacilitator.setIsMonolingualUser(isMonolingualUser); mPersonalizationHelper.setIsMonolingualUser(isMonolingualUser);
} }
public Locale getLocale() { public Locale getLocale() {
@ -226,76 +226,105 @@ public class DictionaryFacilitator {
usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */); usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */);
} }
public void resetDictionariesWithDictNamePrefix(final Context context, final Locale newLocale, public void resetDictionariesWithDictNamePrefix(final Context context,
final Locale newLocaleToUse,
final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean useContactsDict, final boolean usePersonalizedDicts,
final boolean forceReloadMainDictionary, final boolean forceReloadMainDictionary,
final DictionaryInitializationListener listener, final DictionaryInitializationListener listener,
final String dictNamePrefix) { final String dictNamePrefix) {
final boolean localeHasBeenChanged = !newLocale.equals(mDictionaryGroup.mLocale); final HashMap<Locale, ArrayList<String>> existingDictsToCleanup = new HashMap<>();
// We always try to have the main dictionary. Other dictionaries can be unused. // TODO: use several locales
final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary; final Locale[] newLocales = new Locale[] { newLocaleToUse };
// TODO: Make subDictTypesToUse configurable by resource or a static final list. // TODO: Make subDictTypesToUse configurable by resource or a static final list.
final HashSet<String> subDictTypesToUse = new HashSet<>(); final HashSet<String> subDictTypesToUse = new HashSet<>();
subDictTypesToUse.add(Dictionary.TYPE_USER);
if (useContactsDict) { if (useContactsDict) {
subDictTypesToUse.add(Dictionary.TYPE_CONTACTS); subDictTypesToUse.add(Dictionary.TYPE_CONTACTS);
} }
subDictTypesToUse.add(Dictionary.TYPE_USER);
if (usePersonalizedDicts) { if (usePersonalizedDicts) {
subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY); subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY);
subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION); subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION);
subDictTypesToUse.add(Dictionary.TYPE_CONTEXTUAL); subDictTypesToUse.add(Dictionary.TYPE_CONTEXTUAL);
} }
final Dictionary newMainDict; // Gather all dictionaries. We'll remove them from the list to clean up later.
if (reloadMainDictionary) { for (final Locale newLocale : newLocales) {
// The main dictionary will be asynchronously loaded. final ArrayList<String> dictsForLocale = new ArrayList<>();
newMainDict = null; existingDictsToCleanup.put(newLocale, dictsForLocale);
} else { final DictionaryGroup currentDictionaryGroupForLocale =
newMainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN); newLocale.equals(mDictionaryGroup.mLocale) ? mDictionaryGroup : null;
} if (null == currentDictionaryGroupForLocale) {
final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>();
for (final String dictType : SUB_DICT_TYPES) {
if (!subDictTypesToUse.contains(dictType)) {
// This dictionary will not be used.
continue; continue;
} }
final ExpandableBinaryDictionary dict; for (final String dictType : SUB_DICT_TYPES) {
if (!localeHasBeenChanged && mDictionaryGroup.hasDict(dictType)) { if (currentDictionaryGroupForLocale.hasDict(dictType)) {
// Continue to use current dictionary. dictsForLocale.add(dictType);
dict = mDictionaryGroup.getSubDict(dictType); }
} else { }
// Start to use new dictionary. if (currentDictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN)) {
dict = getSubDict(dictType, context, newLocale, null /* dictFile */, dictsForLocale.add(Dictionary.TYPE_MAIN);
dictNamePrefix);
} }
subDicts.put(dictType, dict);
} }
// Replace DictionaryGroup. final HashMap<Locale, DictionaryGroup> newDictionaryGroups = new HashMap<>();
final DictionaryGroup newDictionaryGroup = new DictionaryGroup(newLocale, newMainDict, subDicts); for (final Locale newLocale : newLocales) {
final DictionaryGroup dictionaryGroupForLocale =
newLocale.equals(mDictionaryGroup.mLocale) ? mDictionaryGroup : null;
final ArrayList<String> dictsToCleanupForLocale = existingDictsToCleanup.get(newLocale);
final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale);
final Dictionary mainDict;
if (forceReloadMainDictionary || noExistingDictsForThisLocale
|| !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN)) {
mainDict = null;
} else {
mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN);
dictsToCleanupForLocale.remove(Dictionary.TYPE_MAIN);
}
final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>();
for (final String subDictType : subDictTypesToUse) {
final ExpandableBinaryDictionary subDict;
if (noExistingDictsForThisLocale
|| !dictionaryGroupForLocale.hasDict(subDictType)) {
// Create a new dictionary.
subDict = getSubDict(subDictType, context, newLocale, null /* dictFile */,
dictNamePrefix);
} else {
// Reuse the existing dictionary, and don't close it at the end
subDict = dictionaryGroupForLocale.getSubDict(subDictType);
dictsToCleanupForLocale.remove(subDictType);
}
subDicts.put(subDictType, subDict);
}
newDictionaryGroups.put(newLocale, new DictionaryGroup(newLocale, mainDict, subDicts));
}
// Replace Dictionaries.
// TODO: use multiple locales.
final DictionaryGroup newDictionaryGroup = newDictionaryGroups.get(newLocaleToUse);
final DictionaryGroup oldDictionaryGroup; final DictionaryGroup oldDictionaryGroup;
synchronized (mLock) { synchronized (mLock) {
oldDictionaryGroup = mDictionaryGroup; oldDictionaryGroup = mDictionaryGroup;
mDictionaryGroup = newDictionaryGroup; mDictionaryGroup = newDictionaryGroup;
mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context); mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context);
if (reloadMainDictionary) { if (null == newDictionaryGroup.getDict(Dictionary.TYPE_MAIN)) {
asyncReloadMainDictionary(context, newLocale, listener); asyncReloadMainDictionary(context, newLocaleToUse, listener);
} }
} }
if (listener != null) { if (listener != null) {
listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary()); listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
} }
// Clean up old dictionaries. // Clean up old dictionaries.
if (reloadMainDictionary) { for (final Locale localeToCleanUp : existingDictsToCleanup.keySet()) {
oldDictionaryGroup.closeDict(Dictionary.TYPE_MAIN); final ArrayList<String> dictTypesToCleanUp =
} existingDictsToCleanup.get(localeToCleanUp);
for (final String dictType : SUB_DICT_TYPES) { final DictionaryGroup dictionarySetToCleanup = oldDictionaryGroup;
if (localeHasBeenChanged || !subDictTypesToUse.contains(dictType)) { for (final String dictType : dictTypesToCleanUp) {
oldDictionaryGroup.closeDict(dictType); dictionarySetToCleanup.closeDict(dictType);
} }
} }
oldDictionaryGroup.mSubDictMap.clear();
} }
private void asyncReloadMainDictionary(final Context context, final Locale locale, private void asyncReloadMainDictionary(final Context context, final Locale locale,
@ -362,8 +391,8 @@ public class DictionaryFacilitator {
dictionaryGroup.closeDict(dictType); dictionaryGroup.closeDict(dictType);
} }
mDistracterFilter.close(); mDistracterFilter.close();
if (mPersonalizationDictionaryFacilitator != null) { if (mPersonalizationHelper != null) {
mPersonalizationDictionaryFacilitator.close(); mPersonalizationHelper.close();
} }
} }
@ -386,7 +415,7 @@ public class DictionaryFacilitator {
public void flushPersonalizationDictionary() { public void flushPersonalizationDictionary() {
final ExpandableBinaryDictionary personalizationDictUsedForSuggestion = final ExpandableBinaryDictionary personalizationDictUsedForSuggestion =
mDictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION); mDictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION);
mPersonalizationDictionaryFacilitator.flushPersonalizationDictionariesToUpdate( mPersonalizationHelper.flushPersonalizationDictionariesToUpdate(
personalizationDictUsedForSuggestion); personalizationDictUsedForSuggestion);
mDistracterFilter.close(); mDistracterFilter.close();
} }
@ -592,7 +621,7 @@ public class DictionaryFacilitator {
// personalization dictionary. // personalization dictionary.
public void clearPersonalizationDictionary() { public void clearPersonalizationDictionary() {
clearSubDictionary(Dictionary.TYPE_PERSONALIZATION); clearSubDictionary(Dictionary.TYPE_PERSONALIZATION);
mPersonalizationDictionaryFacilitator.clearDictionariesToUpdate(); mPersonalizationHelper.clearDictionariesToUpdate();
} }
public void clearContextualDictionary() { public void clearContextualDictionary() {
@ -603,7 +632,7 @@ public class DictionaryFacilitator {
final PersonalizationDataChunk personalizationDataChunk, final PersonalizationDataChunk personalizationDataChunk,
final SpacingAndPunctuations spacingAndPunctuations, final SpacingAndPunctuations spacingAndPunctuations,
final AddMultipleDictionaryEntriesCallback callback) { final AddMultipleDictionaryEntriesCallback callback) {
mPersonalizationDictionaryFacilitator.addEntriesToPersonalizationDictionariesToUpdate( mPersonalizationHelper.addEntriesToPersonalizationDictionariesToUpdate(
getLocale(), personalizationDataChunk, spacingAndPunctuations, callback); getLocale(), personalizationDataChunk, spacingAndPunctuations, callback);
} }

View File

@ -38,15 +38,15 @@ import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
/** /**
* Class for managing and updating personalization dictionaries. * Class for managing and updating personalization dictionaries.
*/ */
public class PersonalizationDictionaryFacilitator { public class PersonalizationHelperForDictionaryFacilitator {
private final Context mContext; private final Context mContext;
private final DistracterFilter mDistracterFilter; private final DistracterFilter mDistracterFilter;
private final HashMap<String, HashSet<Locale>> mLangToLocalesMap = new HashMap<>(); private final HashMap<String, HashSet<Locale>> mLangToLocalesMap = new HashMap<>();
private final HashMap<Locale, ExpandableBinaryDictionary> mPersonalizationDictsToUpdate = private final HashMap<Locale, ExpandableBinaryDictionary> mPersonalizationDictsToUpdate =
new HashMap<>(); new HashMap<>();
private boolean mIsMonolingualUser = false;; private boolean mIsMonolingualUser = false;
PersonalizationDictionaryFacilitator(final Context context, PersonalizationHelperForDictionaryFacilitator(final Context context,
final DistracterFilter distracterFilter) { final DistracterFilter distracterFilter) {
mContext = context; mContext = context;
mDistracterFilter = distracterFilter; mDistracterFilter = distracterFilter;