Merge "Move distracter filter to dictionary facilitator."

main
Keisuke Kuroyanagi 2014-05-23 07:19:07 +00:00 committed by Android (Google) Code Review
commit fd8c3792d9
7 changed files with 140 additions and 50 deletions

View File

@ -19,14 +19,18 @@ package com.android.inputmethod.latin;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;
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.ContextualDictionary; import com.android.inputmethod.latin.personalization.ContextualDictionary;
import com.android.inputmethod.latin.personalization.PersonalizationDataChunk;
import com.android.inputmethod.latin.personalization.PersonalizationDictionary; import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
import com.android.inputmethod.latin.personalization.UserHistoryDictionary; import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.DistracterFilter;
import com.android.inputmethod.latin.utils.ExecutorUtils; import com.android.inputmethod.latin.utils.ExecutorUtils;
import com.android.inputmethod.latin.utils.LanguageModelParam; import com.android.inputmethod.latin.utils.LanguageModelParam;
import com.android.inputmethod.latin.utils.SuggestionResults; import com.android.inputmethod.latin.utils.SuggestionResults;
@ -37,6 +41,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -57,6 +62,7 @@ public class DictionaryFacilitator {
private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0); private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
// To synchronize assigning mDictionaries to ensure closing dictionaries. // To synchronize assigning mDictionaries to ensure closing dictionaries.
private final Object mLock = new Object(); private final Object mLock = new Object();
private final DistracterFilter mDistracterFilter;
private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION = private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION =
new String[] { new String[] {
@ -162,7 +168,17 @@ public class DictionaryFacilitator {
public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable); public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable);
} }
public DictionaryFacilitator() {} public DictionaryFacilitator() {
mDistracterFilter = new DistracterFilter();
}
public DictionaryFacilitator(final DistracterFilter distracterFilter) {
mDistracterFilter = distracterFilter;
}
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
mDistracterFilter.updateEnabledSubtypes(enabledSubtypes);
}
public Locale getLocale() { public Locale getLocale() {
return mDictionaries.mLocale; return mDictionaries.mLocale;
@ -321,6 +337,7 @@ public class DictionaryFacilitator {
for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) { for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) {
dictionaries.closeDict(dictType); dictionaries.closeDict(dictType);
} }
mDistracterFilter.close();
} }
// The main dictionary could have been loaded asynchronously. Don't cache the return value // The main dictionary could have been loaded asynchronously. Don't cache the return value
@ -537,9 +554,16 @@ public class DictionaryFacilitator {
personalizationDict.clear(); personalizationDict.clear();
} }
public void addMultipleDictionaryEntriesToPersonalizationDictionary( public void addEntriesToPersonalizationDictionary(
final ArrayList<LanguageModelParam> languageModelParams, final PersonalizationDataChunk personalizationDataChunk,
final SpacingAndPunctuations spacingAndPunctuations,
final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) { final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) {
final ArrayList<LanguageModelParam> languageModelParams =
LanguageModelParam.createLanguageModelParamsFrom(
personalizationDataChunk.mTokens,
personalizationDataChunk.mTimestampInSeconds,
this /* dictionaryFacilitator */, spacingAndPunctuations,
mDistracterFilter);
final ExpandableBinaryDictionary personalizationDict = final ExpandableBinaryDictionary personalizationDict =
mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION); mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION);
if (personalizationDict == null || languageModelParams == null if (personalizationDict == null || languageModelParams == null

View File

@ -81,6 +81,7 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripView;
import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
import com.android.inputmethod.latin.utils.ApplicationUtils; import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils; import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.CoordinateUtils;
import com.android.inputmethod.latin.utils.DialogUtils; import com.android.inputmethod.latin.utils.DialogUtils;
import com.android.inputmethod.latin.utils.DistracterFilter; import com.android.inputmethod.latin.utils.DistracterFilter;
@ -95,6 +96,7 @@ import com.android.inputmethod.research.ResearchLogger;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -122,7 +124,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final String SCHEME_PACKAGE = "package"; private static final String SCHEME_PACKAGE = "package";
private final Settings mSettings; private final Settings mSettings;
private final DictionaryFacilitator mDictionaryFacilitator = new DictionaryFacilitator(); private final DictionaryFacilitator mDictionaryFacilitator =
new DictionaryFacilitator(new DistracterFilter(this /* context */));
private final InputLogic mInputLogic = new InputLogic(this /* LatinIME */, private final InputLogic mInputLogic = new InputLogic(this /* LatinIME */,
this /* SuggestionStripViewAccessor */, mDictionaryFacilitator); this /* SuggestionStripViewAccessor */, mDictionaryFacilitator);
// We expect to have only one decoder in almost all cases, hence the default capacity of 1. // We expect to have only one decoder in almost all cases, hence the default capacity of 1.
@ -538,6 +541,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!mHandler.hasPendingReopenDictionaries()) { if (!mHandler.hasPendingReopenDictionaries()) {
resetSuggestForLocale(locale); resetSuggestForLocale(locale);
} }
mDictionaryFacilitator.updateEnabledSubtypes(mRichImm.getMyEnabledInputMethodSubtypeList(
true /* allowsImplicitlySelectedSubtypes */));
refreshPersonalizationDictionarySession(); refreshPersonalizationDictionarySession();
StatsUtils.onLoadSettings(currentSettingsValues); StatsUtils.onLoadSettings(currentSettingsValues);
} }
@ -564,9 +569,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
PersonalizationHelper.removeAllPersonalizationDictionaries(this); PersonalizationHelper.removeAllPersonalizationDictionaries(this);
PersonalizationDictionarySessionRegistrar.resetAll(this); PersonalizationDictionarySessionRegistrar.resetAll(this);
} else { } else {
final DistracterFilter distracterFilter = createDistracterFilter(); PersonalizationDictionarySessionRegistrar.init(this, mDictionaryFacilitator);
PersonalizationDictionarySessionRegistrar.init(
this, mDictionaryFacilitator, distracterFilter);
} }
} }
@ -660,9 +663,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mInputLogic.mConnection.finishComposingText(); mInputLogic.mConnection.finishComposingText();
mInputLogic.mConnection.endBatchEdit(); mInputLogic.mConnection.endBatchEdit();
} }
final DistracterFilter distracterFilter = createDistracterFilter();
PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf, PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf,
mDictionaryFacilitator, distracterFilter); mDictionaryFacilitator);
super.onConfigurationChanged(conf); super.onConfigurationChanged(conf);
} }
@ -1739,11 +1741,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
@UsedForTesting @UsedForTesting
/* package for test */ DistracterFilter createDistracterFilter() { /* package for test */ List<InputMethodSubtype> getEnabledSubtypesForTest() {
// Return an empty distracter filter when this method is called before onCreate(). return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList(
return (mRichImm != null) ? new DistracterFilter(this /* Context */, true /* allowsImplicitlySelectedSubtypes */) : new ArrayList<InputMethodSubtype>();
mRichImm.getMyEnabledInputMethodSubtypeList(
true /* allowsImplicitlySelectedSubtypes */)) : new DistracterFilter();
} }
public void dumpDictionaryForDebug(final String dictName) { public void dumpDictionaryForDebug(final String dictName) {

View File

@ -0,0 +1,37 @@
/*
* 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.personalization;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public class PersonalizationDataChunk {
public final boolean mInputByUser;
public final List<String> mTokens;
public final int mTimestampInSeconds;
public final String mPackageName;
public final Locale mlocale = null;
public PersonalizationDataChunk(boolean inputByUser, final List<String> tokens,
final int timestampInSeconds, final String packageName) {
mInputByUser = inputByUser;
mTokens = Collections.unmodifiableList(tokens);
mTimestampInSeconds = timestampInSeconds;
mPackageName = packageName;
}
}

View File

@ -20,17 +20,14 @@ import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.DictionaryFacilitator;
import com.android.inputmethod.latin.utils.DistracterFilter;
public class PersonalizationDictionarySessionRegistrar { public class PersonalizationDictionarySessionRegistrar {
public static void init(final Context context, public static void init(final Context context,
final DictionaryFacilitator dictionaryFacilitator, final DictionaryFacilitator dictionaryFacilitator) {
final DistracterFilter distracterFilter) {
} }
public static void onConfigurationChanged(final Context context, final Configuration conf, public static void onConfigurationChanged(final Context context, final Configuration conf,
final DictionaryFacilitator dictionaryFacilitator, final DictionaryFacilitator dictionaryFacilitator) {
final DistracterFilter distracterFilter) {
} }
public static void onUpdateData(final Context context, final String type) { public static void onUpdateData(final Context context, final String type) {

View File

@ -16,7 +16,6 @@
package com.android.inputmethod.latin.utils; package com.android.inputmethod.latin.utils;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -57,6 +56,7 @@ public class DistracterFilter {
private final DictionaryFacilitator mDictionaryFacilitator; private final DictionaryFacilitator mDictionaryFacilitator;
private final Suggest mSuggest; private final Suggest mSuggest;
private Keyboard mKeyboard; private Keyboard mKeyboard;
private final Object mLock = new Object();
// If the score of the top suggestion exceeds this value, the tested word (e.g., // If the score of the top suggestion exceeds this value, the tested word (e.g.,
// an OOV, a misspelling, or an in-vocabulary word) would be considered as a distracter to // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distracter to
@ -67,35 +67,59 @@ public class DistracterFilter {
// Create empty distracter filter. // Create empty distracter filter.
public DistracterFilter() { public DistracterFilter() {
this(null, new ArrayList<InputMethodSubtype>()); mContext = null;
mLocaleToSubtypeMap = new HashMap<>();
mLocaleToKeyboardMap = new HashMap<>();
// TODO: Quit assigning null.
mDictionaryFacilitator = null;
mSuggest = null;
mKeyboard = null;
} }
/** /**
* Create a DistracterFilter instance. * Create a DistracterFilter instance.
* *
* @param context the context. * @param context the context.
* @param enabledSubtypes the enabled subtypes.
*/ */
public DistracterFilter(final Context context, final List<InputMethodSubtype> enabledSubtypes) { public DistracterFilter(final Context context) {
mContext = context; mContext = context;
mLocaleToSubtypeMap = new HashMap<>(); mLocaleToSubtypeMap = new HashMap<>();
if (enabledSubtypes != null) {
for (final InputMethodSubtype subtype : enabledSubtypes) {
final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
if (mLocaleToSubtypeMap.containsKey(locale)) {
// Multiple subtypes are enabled for one locale.
// TODO: Investigate what we should do for this case.
continue;
}
mLocaleToSubtypeMap.put(locale, subtype);
}
}
mLocaleToKeyboardMap = new HashMap<>(); mLocaleToKeyboardMap = new HashMap<>();
mDictionaryFacilitator = new DictionaryFacilitator(); mDictionaryFacilitator = new DictionaryFacilitator();
mSuggest = new Suggest(mDictionaryFacilitator); mSuggest = new Suggest(mDictionaryFacilitator);
mKeyboard = null; mKeyboard = null;
} }
public void close() {
if (mDictionaryFacilitator != null) {
mDictionaryFacilitator.closeDictionaries();
}
}
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
final Map<Locale, InputMethodSubtype> newLocaleToSubtypeMap = new HashMap<>();
if (enabledSubtypes != null) {
for (final InputMethodSubtype subtype : enabledSubtypes) {
final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
if (newLocaleToSubtypeMap.containsKey(locale)) {
// Multiple subtypes are enabled for one locale.
// TODO: Investigate what we should do for this case.
continue;
}
newLocaleToSubtypeMap.put(locale, subtype);
}
}
if (mLocaleToSubtypeMap.equals(newLocaleToSubtypeMap)) {
// Enabled subtypes have not been changed.
return;
}
synchronized (mLock) {
mLocaleToSubtypeMap.clear();
mLocaleToSubtypeMap.putAll(newLocaleToSubtypeMap);
mLocaleToKeyboardMap.clear();
}
}
private static boolean suggestionExceedsDistracterThreshold( private static boolean suggestionExceedsDistracterThreshold(
final SuggestedWordInfo suggestion, final String consideredWord, final SuggestedWordInfo suggestion, final String consideredWord,
final float distracterThreshold) { final float distracterThreshold) {
@ -116,7 +140,10 @@ public class DistracterFilter {
mKeyboard = cachedKeyboard; mKeyboard = cachedKeyboard;
return; return;
} }
final InputMethodSubtype subtype = mLocaleToSubtypeMap.get(newLocale); final InputMethodSubtype subtype;
synchronized (mLock) {
subtype = mLocaleToSubtypeMap.get(newLocale);
}
if (subtype == null) { if (subtype == null) {
return; return;
} }
@ -153,10 +180,11 @@ public class DistracterFilter {
*/ */
public boolean isDistracterToWordsInDictionaries(final PrevWordsInfo prevWordsInfo, public boolean isDistracterToWordsInDictionaries(final PrevWordsInfo prevWordsInfo,
final String testedWord, final Locale locale) { final String testedWord, final Locale locale) {
if (locale == null) { if (mSuggest == null || locale == null) {
return false; return false;
} }
if (!locale.equals(mDictionaryFacilitator.getLocale())) { if (!locale.equals(mDictionaryFacilitator.getLocale())) {
synchronized (mLock) {
if (!mLocaleToSubtypeMap.containsKey(locale)) { if (!mLocaleToSubtypeMap.containsKey(locale)) {
Log.e(TAG, "Locale " + locale + " is not enabled."); Log.e(TAG, "Locale " + locale + " is not enabled.");
// TODO: Investigate what we should do for disabled locales. // TODO: Investigate what we should do for disabled locales.
@ -167,10 +195,12 @@ public class DistracterFilter {
try { try {
loadDictionariesForLocale(locale); loadDictionariesForLocale(locale);
} catch (final InterruptedException e) { } catch (final InterruptedException e) {
Log.e(TAG, "Interrupted while waiting for loading dicts in DistracterFilter", e); Log.e(TAG, "Interrupted while waiting for loading dicts in DistracterFilter",
e);
return false; return false;
} }
} }
}
if (mKeyboard == null) { if (mKeyboard == null) {
return false; return false;
} }

View File

@ -24,6 +24,7 @@ import com.android.inputmethod.latin.PrevWordsInfo;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
// Note: this class is used as a parameter type of a native method. You should be careful when you // Note: this class is used as a parameter type of a native method. You should be careful when you
@ -79,7 +80,7 @@ public final class LanguageModelParam {
// Process a list of words and return a list of {@link LanguageModelParam} objects. // Process a list of words and return a list of {@link LanguageModelParam} objects.
public static ArrayList<LanguageModelParam> createLanguageModelParamsFrom( public static ArrayList<LanguageModelParam> createLanguageModelParamsFrom(
final ArrayList<String> tokens, final int timestamp, final List<String> tokens, final int timestamp,
final DictionaryFacilitator dictionaryFacilitator, final DictionaryFacilitator dictionaryFacilitator,
final SpacingAndPunctuations spacingAndPunctuations, final SpacingAndPunctuations spacingAndPunctuations,
final DistracterFilter distracterFilter) { final DistracterFilter distracterFilter) {

View File

@ -32,7 +32,8 @@ public class DistracterFilterTest extends InputTestsBase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
mDistracterFilter = mLatinIME.createDistracterFilter(); mDistracterFilter = new DistracterFilter(getContext());
mDistracterFilter.updateEnabledSubtypes(mLatinIME.getEnabledSubtypesForTest());
} }
public void testIsDistractorToWordsInDictionaries() { public void testIsDistractorToWordsInDictionaries() {