Simplify DictionaryFacilitatorForSuggest.

Bug: 13755213
Change-Id: I9663d1d60fccd8deb1a22683fb06fe64dee06b45
main
Keisuke Kuroyanagi 2014-05-01 15:51:03 +09:00
parent 9ed7e47539
commit 1ab6bfdc60
3 changed files with 83 additions and 124 deletions

View File

@ -23,7 +23,7 @@ import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.personalization.PersonalizationDictionary; import com.android.inputmethod.latin.personalization.DecayingExpandableBinaryDictionaryBase;
import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.personalization.UserHistoryDictionary; import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CollectionUtils;
@ -33,9 +33,11 @@ import com.android.inputmethod.latin.utils.SuggestionResults;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -54,7 +56,7 @@ public class DictionaryFacilitatorForSuggest {
// To synchronize assigning mDictionaries to ensure closing dictionaries. // To synchronize assigning mDictionaries to ensure closing dictionaries.
private Object mLock = new Object(); private Object mLock = new Object();
private static final String[] dictTypesOrderedToGetSuggestion = private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION =
new String[] { new String[] {
Dictionary.TYPE_MAIN, Dictionary.TYPE_MAIN,
Dictionary.TYPE_USER_HISTORY, Dictionary.TYPE_USER_HISTORY,
@ -63,6 +65,10 @@ public class DictionaryFacilitatorForSuggest {
Dictionary.TYPE_CONTACTS Dictionary.TYPE_CONTACTS
}; };
private static final String[] SUB_DICT_TYPES =
Arrays.copyOfRange(DICT_TYPES_ORDERED_TO_GET_SUGGESTION, 1 /* start */,
DICT_TYPES_ORDERED_TO_GET_SUGGESTION.length);
/** /**
* Class contains dictionaries for a locale. * Class contains dictionaries for a locale.
*/ */
@ -78,17 +84,13 @@ public class DictionaryFacilitatorForSuggest {
} }
public Dictionaries(final Locale locale, final Dictionary mainDict, public Dictionaries(final Locale locale, final Dictionary mainDict,
final ExpandableBinaryDictionary contactsDict, final Map<String, ExpandableBinaryDictionary> subDicts) {
final ExpandableBinaryDictionary userDict,
final ExpandableBinaryDictionary userHistoryDict,
final ExpandableBinaryDictionary personalizationDict) {
mLocale = locale; mLocale = locale;
// Main dictionary can be asynchronously loaded. // Main dictionary can be asynchronously loaded.
setMainDict(mainDict); setMainDict(mainDict);
setSubDict(Dictionary.TYPE_CONTACTS, contactsDict); for (final Map.Entry<String, ExpandableBinaryDictionary> entry : subDicts.entrySet()) {
setSubDict(Dictionary.TYPE_USER, userDict); setSubDict(entry.getKey(), entry.getValue());
setSubDict(Dictionary.TYPE_USER_HISTORY, userHistoryDict); }
setSubDict(Dictionary.TYPE_PERSONALIZATION, personalizationDict);
} }
private void setSubDict(final String dictType, final ExpandableBinaryDictionary dict) { private void setSubDict(final String dictType, final ExpandableBinaryDictionary dict) {
@ -142,6 +144,21 @@ public class DictionaryFacilitatorForSuggest {
return mDictionaries.mLocale; return mDictionaries.mLocale;
} }
private static ExpandableBinaryDictionary getSubDict(final String dictType,
final Context context, final Locale locale, final File dictFile) {
if (Dictionary.TYPE_CONTACTS.equals(dictType)) {
return new ContactsBinaryDictionary(context, locale, dictFile);
} else if (Dictionary.TYPE_USER.equals(dictType)) {
return new UserBinaryDictionary(context, locale, dictFile);
} else if (Dictionary.TYPE_USER_HISTORY.equals(dictType)) {
return PersonalizationHelper.getUserHistoryDictionary(context, locale);
} else if (Dictionary.TYPE_PERSONALIZATION.equals(dictType)) {
return PersonalizationHelper.getPersonalizationDictionary(context, locale);
} else {
return null;
}
}
public void resetDictionaries(final Context context, final Locale newLocale, public void resetDictionaries(final Context context, final Locale newLocale,
final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean useContactsDict, final boolean usePersonalizedDicts,
final boolean forceReloadMainDictionary, final boolean forceReloadMainDictionary,
@ -149,11 +166,15 @@ public class DictionaryFacilitatorForSuggest {
final boolean localeHasBeenChanged = !newLocale.equals(mDictionaries.mLocale); final boolean localeHasBeenChanged = !newLocale.equals(mDictionaries.mLocale);
// We always try to have the main dictionary. Other dictionaries can be unused. // We always try to have the main dictionary. Other dictionaries can be unused.
final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary; final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary;
final boolean closeContactsDictionary = localeHasBeenChanged || !useContactsDict; final Set<String> subDictTypesToUse = CollectionUtils.newHashSet();
final boolean closeUserDictionary = localeHasBeenChanged; if (useContactsDict) {
final boolean closeUserHistoryDictionary = localeHasBeenChanged || !usePersonalizedDicts; subDictTypesToUse.add(Dictionary.TYPE_USER);
final boolean closePersonalizationDictionary = }
localeHasBeenChanged || !usePersonalizedDicts; subDictTypesToUse.add(Dictionary.TYPE_USER);
if (usePersonalizedDicts) {
subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY);
subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION);
}
final Dictionary newMainDict; final Dictionary newMainDict;
if (reloadMainDictionary) { if (reloadMainDictionary) {
@ -163,50 +184,25 @@ public class DictionaryFacilitatorForSuggest {
newMainDict = mDictionaries.getMainDict(); newMainDict = mDictionaries.getMainDict();
} }
// Open or move contacts dictionary. final Map<String, ExpandableBinaryDictionary> subDicts = CollectionUtils.newHashMap();
final ExpandableBinaryDictionary newContactsDict; for (final String dictType : SUB_DICT_TYPES) {
if (!closeContactsDictionary && mDictionaries.hasDict(Dictionary.TYPE_CONTACTS)) { if (!subDictTypesToUse.contains(dictType)) {
newContactsDict = mDictionaries.getSubDict(Dictionary.TYPE_CONTACTS); // This dictionary will not be used.
} else if (useContactsDict) { continue;
newContactsDict = new ContactsBinaryDictionary(context, newLocale);
} else {
newContactsDict = null;
} }
final ExpandableBinaryDictionary dict;
// Open or move user dictionary. if (!localeHasBeenChanged && mDictionaries.hasDict(dictType)) {
final ExpandableBinaryDictionary newUserDictionary; // Continue to use current dictionary.
if (!closeUserDictionary && mDictionaries.hasDict(Dictionary.TYPE_USER)) { dict = mDictionaries.getSubDict(dictType);
newUserDictionary = mDictionaries.getSubDict(Dictionary.TYPE_USER);
} else { } else {
newUserDictionary = new UserBinaryDictionary(context, newLocale); // Start to use new dictionary.
mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context); dict = getSubDict(dictType, context, newLocale, null /* dictFile */);
} }
subDicts.put(dictType, dict);
// Open or move user history dictionary.
final ExpandableBinaryDictionary newUserHistoryDict;
if (!closeUserHistoryDictionary && mDictionaries.hasDict(Dictionary.TYPE_USER_HISTORY)) {
newUserHistoryDict = mDictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY);
} else if (usePersonalizedDicts) {
newUserHistoryDict = PersonalizationHelper.getUserHistoryDictionary(context, newLocale);
} else {
newUserHistoryDict = null;
}
// Open or move personalization dictionary.
final ExpandableBinaryDictionary newPersonalizationDict;
if (!closePersonalizationDictionary
&& mDictionaries.hasDict(Dictionary.TYPE_PERSONALIZATION)) {
newPersonalizationDict = mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION);
} else if (usePersonalizedDicts) {
newPersonalizationDict =
PersonalizationHelper.getPersonalizationDictionary(context, newLocale);
} else {
newPersonalizationDict = null;
} }
// Replace Dictionaries. // Replace Dictionaries.
final Dictionaries newDictionaries = new Dictionaries(newLocale, newMainDict, final Dictionaries newDictionaries = new Dictionaries(newLocale, newMainDict, subDicts);
newContactsDict, newUserDictionary, newUserHistoryDict, newPersonalizationDict);
final Dictionaries oldDictionaries; final Dictionaries oldDictionaries;
synchronized (mLock) { synchronized (mLock) {
oldDictionaries = mDictionaries; oldDictionaries = mDictionaries;
@ -218,22 +214,14 @@ public class DictionaryFacilitatorForSuggest {
if (listener != null) { if (listener != null) {
listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary()); listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
} }
// Clean up old dictionaries. // Clean up old dictionaries.
if (reloadMainDictionary) { if (reloadMainDictionary) {
oldDictionaries.closeDict(Dictionary.TYPE_MAIN); oldDictionaries.closeDict(Dictionary.TYPE_MAIN);
} }
if (closeContactsDictionary) { for (final String dictType : SUB_DICT_TYPES) {
oldDictionaries.closeDict(Dictionary.TYPE_CONTACTS); if (localeHasBeenChanged || !subDictTypesToUse.contains(dictType)) {
oldDictionaries.closeDict(dictType);
} }
if (closeUserDictionary) {
oldDictionaries.closeDict(Dictionary.TYPE_USER);
}
if (closeUserHistoryDictionary) {
oldDictionaries.closeDict(Dictionary.TYPE_USER_HISTORY);
}
if (closePersonalizationDictionary) {
oldDictionaries.closeDict(Dictionary.TYPE_PERSONALIZATION);
} }
oldDictionaries.mDictMap.clear(); oldDictionaries.mDictMap.clear();
oldDictionaries.mSubDictMap.clear(); oldDictionaries.mSubDictMap.clear();
@ -269,52 +257,28 @@ public class DictionaryFacilitatorForSuggest {
final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles,
final Map<String, Map<String, String>> additionalDictAttributes) { final Map<String, Map<String, String>> additionalDictAttributes) {
Dictionary mainDictionary = null; Dictionary mainDictionary = null;
ContactsBinaryDictionary contactsDictionary = null; final Map<String, ExpandableBinaryDictionary> subDicts = CollectionUtils.newHashMap();
UserBinaryDictionary userDictionary = null;
UserHistoryDictionary userHistoryDictionary = null;
PersonalizationDictionary personalizationDictionary = null;
for (final String dictType : dictionaryTypes) { for (final String dictType : dictionaryTypes) {
if (dictType.equals(Dictionary.TYPE_MAIN)) { if (dictType.equals(Dictionary.TYPE_MAIN)) {
mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, locale); mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, locale);
} else if (dictType.equals(Dictionary.TYPE_USER_HISTORY)) {
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();
if (additionalDictAttributes.containsKey(dictType)) {
userHistoryDictionary.clearAndFlushDictionaryWithAdditionalAttributes(
additionalDictAttributes.get(dictType));
}
} else if (dictType.equals(Dictionary.TYPE_PERSONALIZATION)) {
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();
if (additionalDictAttributes.containsKey(dictType)) {
personalizationDictionary.clearAndFlushDictionaryWithAdditionalAttributes(
additionalDictAttributes.get(dictType));
}
} else if (dictType.equals(Dictionary.TYPE_USER)) {
final File file = dictionaryFiles.get(dictType);
userDictionary = new UserBinaryDictionary(context, locale, file);
userDictionary.reloadDictionaryIfRequired();
userDictionary.waitAllTasksForTests();
} else if (dictType.equals(Dictionary.TYPE_CONTACTS)) {
final File file = dictionaryFiles.get(dictType);
contactsDictionary = new ContactsBinaryDictionary(context, locale, file);
contactsDictionary.reloadDictionaryIfRequired();
contactsDictionary.waitAllTasksForTests();
} else { } else {
final File dictFile = dictionaryFiles.get(dictType);
final ExpandableBinaryDictionary dict = getSubDict(
dictType, context, locale, dictFile);
if (additionalDictAttributes.containsKey(dictType)) {
dict.clearAndFlushDictionaryWithAdditionalAttributes(
additionalDictAttributes.get(dictType));
}
if (dict == null) {
throw new RuntimeException("Unknown dictionary type: " + dictType); throw new RuntimeException("Unknown dictionary type: " + dictType);
} }
dict.reloadDictionaryIfRequired();
dict.waitAllTasksForTests();
subDicts.put(dictType, dict);
} }
mDictionaries = new Dictionaries(locale, mainDictionary, contactsDictionary, }
userDictionary, userHistoryDictionary, personalizationDictionary); mDictionaries = new Dictionaries(locale, mainDictionary, subDicts);
} }
public void closeDictionaries() { public void closeDictionaries() {
@ -443,7 +407,7 @@ public class DictionaryFacilitatorForSuggest {
final SuggestionResults suggestionResults = final SuggestionResults suggestionResults =
new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS); new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS);
final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT }; final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
for (final String dictType : dictTypesOrderedToGetSuggestion) { for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) {
final Dictionary dictionary = dictMap.get(dictType); final Dictionary dictionary = dictMap.get(dictType);
if (null == dictionary) continue; if (null == dictionary) continue;
final ArrayList<SuggestedWordInfo> dictionarySuggestions = final ArrayList<SuggestedWordInfo> dictionarySuggestions =

View File

@ -97,6 +97,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
private final ReentrantReadWriteLock mLock; private final ReentrantReadWriteLock mLock;
private Map<String, String> mAdditionalAttributeMap = null;
/* A extension for a binary dictionary file. */ /* A extension for a binary dictionary file. */
protected static final String DICT_FILE_EXTENSION = ".dict"; protected static final String DICT_FILE_EXTENSION = ".dict";
@ -196,6 +198,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
protected Map<String, String> getHeaderAttributeMap() { protected Map<String, String> getHeaderAttributeMap() {
HashMap<String, String> attributeMap = new HashMap<String, String>(); HashMap<String, String> attributeMap = new HashMap<String, String>();
if (mAdditionalAttributeMap != null) {
attributeMap.putAll(mAdditionalAttributeMap);
}
attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, mDictName); attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, mDictName);
attributeMap.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, mLocale.toString()); attributeMap.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, mLocale.toString());
attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY,
@ -591,6 +596,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
} }
@UsedForTesting @UsedForTesting
public void clearAndFlushDictionaryWithAdditionalAttributes(
final Map<String, String> attributeMap) {
mAdditionalAttributeMap = attributeMap;
clear();
}
public void dumpAllWordsForDebug() { public void dumpAllWordsForDebug() {
reloadDictionaryIfRequired(); reloadDictionaryIfRequired();
asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() { asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() {

View File

@ -18,15 +18,11 @@ package com.android.inputmethod.latin.personalization;
import android.content.Context; import android.content.Context;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.ExpandableBinaryDictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary;
import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.DictionaryHeader;
import com.android.inputmethod.latin.utils.LanguageModelParam;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -47,8 +43,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
/** The locale for this dictionary. */ /** The locale for this dictionary. */
public final Locale mLocale; public final Locale mLocale;
private Map<String, String> mAdditionalAttributeMap = null;
protected DecayingExpandableBinaryDictionaryBase(final Context context, protected DecayingExpandableBinaryDictionaryBase(final Context context,
final String dictName, final Locale locale, final String dictionaryType, final String dictName, final Locale locale, final String dictionaryType,
final File dictFile) { final File dictFile) {
@ -72,9 +66,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
@Override @Override
protected Map<String, String> getHeaderAttributeMap() { protected Map<String, String> getHeaderAttributeMap() {
final Map<String, String> attributeMap = super.getHeaderAttributeMap(); final Map<String, String> attributeMap = super.getHeaderAttributeMap();
if (mAdditionalAttributeMap != null) {
attributeMap.putAll(mAdditionalAttributeMap);
}
attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY,
DictionaryHeader.ATTRIBUTE_VALUE_TRUE); DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY,
@ -92,13 +83,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
// No initial contents. // No initial contents.
} }
@UsedForTesting
public void clearAndFlushDictionaryWithAdditionalAttributes(
final Map<String, String> attributeMap) {
mAdditionalAttributeMap = attributeMap;
clear();
}
/* package */ void runGCIfRequired() { /* package */ void runGCIfRequired() {
runGCIfRequired(false /* mindsBlockByGC */); runGCIfRequired(false /* mindsBlockByGC */);
} }