parent
174da5c395
commit
15acbdc905
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 android.content.Context;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitator;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class ContextualDictionaryUpdater {
|
|
||||||
public ContextualDictionaryUpdater(final Context context,
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator,
|
|
||||||
final Runnable onUpdateRunnable) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onLoadSettings(final boolean usePersonalizedDicts) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartInputView(final String packageName) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDestroy() {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 android.content.Context;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitator;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class PersonalizationDictionaryUpdater {
|
|
||||||
final Context mContext;
|
|
||||||
final DictionaryFacilitator mDictionaryFacilitator;
|
|
||||||
boolean mDictCleared = false;
|
|
||||||
|
|
||||||
public PersonalizationDictionaryUpdater(final Context context,
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator) {
|
|
||||||
mContext = context;
|
|
||||||
mDictionaryFacilitator = dictionaryFacilitator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onLoadSettings(final boolean usePersonalizedDicts) {
|
|
||||||
if (!mDictCleared) {
|
|
||||||
// Clear and never update the personalization dictionary.
|
|
||||||
PersonalizationHelper.removeAllPersonalizationDictionaries(mContext);
|
|
||||||
mDictionaryFacilitator.clearPersonalizationDictionary();
|
|
||||||
mDictCleared = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDestroy() {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,21 +17,18 @@
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback;
|
|
||||||
import com.android.inputmethod.latin.personalization.PersonalizationDataChunk;
|
|
||||||
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
|
||||||
import com.android.inputmethod.latin.utils.SuggestionResults;
|
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.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -120,8 +117,6 @@ public interface DictionaryFacilitator {
|
||||||
|
|
||||||
boolean hasPersonalizationDictionary();
|
boolean hasPersonalizationDictionary();
|
||||||
|
|
||||||
void flushPersonalizationDictionary();
|
|
||||||
|
|
||||||
void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
|
void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
|
||||||
throws InterruptedException;
|
throws InterruptedException;
|
||||||
|
|
||||||
|
@ -152,21 +147,6 @@ public interface DictionaryFacilitator {
|
||||||
|
|
||||||
void clearUserHistoryDictionary();
|
void clearUserHistoryDictionary();
|
||||||
|
|
||||||
// This method gets called only when the IME receives a notification to remove the
|
|
||||||
// personalization dictionary.
|
|
||||||
void clearPersonalizationDictionary();
|
|
||||||
|
|
||||||
void clearContextualDictionary();
|
|
||||||
|
|
||||||
void addEntriesToPersonalizationDictionary(
|
|
||||||
final PersonalizationDataChunk personalizationDataChunk,
|
|
||||||
final SpacingAndPunctuations spacingAndPunctuations,
|
|
||||||
final UpdateEntriesForInputEventsCallback callback);
|
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
void addPhraseToContextualDictionary(final String[] phrase, final int probability,
|
|
||||||
final int bigramProbabilityForWords, final int bigramProbabilityForPhrases);
|
|
||||||
|
|
||||||
void dumpDictionaryForDebug(final String dictName);
|
void dumpDictionaryForDebug(final String dictName);
|
||||||
|
|
||||||
ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts();
|
ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts();
|
||||||
|
|
|
@ -23,16 +23,11 @@ import android.util.Pair;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback;
|
|
||||||
import com.android.inputmethod.latin.NgramContext.WordInfo;
|
import com.android.inputmethod.latin.NgramContext.WordInfo;
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||||
import com.android.inputmethod.latin.common.Constants;
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
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.UserHistoryDictionary;
|
import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
|
||||||
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
|
||||||
import com.android.inputmethod.latin.utils.DistracterFilter;
|
import com.android.inputmethod.latin.utils.DistracterFilter;
|
||||||
import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
|
import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
|
||||||
import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary;
|
import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary;
|
||||||
|
@ -83,16 +78,13 @@ public class DictionaryFacilitatorImpl implements 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 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[] {
|
||||||
Dictionary.TYPE_MAIN,
|
Dictionary.TYPE_MAIN,
|
||||||
Dictionary.TYPE_USER_HISTORY,
|
Dictionary.TYPE_USER_HISTORY,
|
||||||
Dictionary.TYPE_PERSONALIZATION,
|
|
||||||
Dictionary.TYPE_USER,
|
Dictionary.TYPE_USER,
|
||||||
Dictionary.TYPE_CONTACTS,
|
Dictionary.TYPE_CONTACTS,
|
||||||
Dictionary.TYPE_CONTEXTUAL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Map<String, Class<? extends ExpandableBinaryDictionary>>
|
public static final Map<String, Class<? extends ExpandableBinaryDictionary>>
|
||||||
|
@ -100,10 +92,8 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER_HISTORY, UserHistoryDictionary.class);
|
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER_HISTORY, UserHistoryDictionary.class);
|
||||||
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_PERSONALIZATION, PersonalizationDictionary.class);
|
|
||||||
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER, UserBinaryDictionary.class);
|
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER, UserBinaryDictionary.class);
|
||||||
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTACTS, ContactsBinaryDictionary.class);
|
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTACTS, ContactsBinaryDictionary.class);
|
||||||
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTEXTUAL, ContextualDictionary.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String DICT_FACTORY_METHOD_NAME = "getDictionary";
|
private static final String DICT_FACTORY_METHOD_NAME = "getDictionary";
|
||||||
|
@ -257,23 +247,18 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
||||||
|
|
||||||
public DictionaryFacilitatorImpl() {
|
public DictionaryFacilitatorImpl() {
|
||||||
mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER;
|
mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER;
|
||||||
mPersonalizationHelper = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DictionaryFacilitatorImpl(final Context context) {
|
public DictionaryFacilitatorImpl(final Context context) {
|
||||||
mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context);
|
mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context);
|
||||||
mPersonalizationHelper =
|
|
||||||
new PersonalizationHelperForDictionaryFacilitator(context, mDistracterFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
|
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
|
||||||
mDistracterFilter.updateEnabledSubtypes(enabledSubtypes);
|
mDistracterFilter.updateEnabledSubtypes(enabledSubtypes);
|
||||||
mPersonalizationHelper.updateEnabledSubtypes(enabledSubtypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this, it's confusing with seamless multiple language switching
|
// TODO: remove this, it's confusing with seamless multiple language switching
|
||||||
public void setIsMonolingualUser(final boolean isMonolingualUser) {
|
public void setIsMonolingualUser(final boolean isMonolingualUser) {
|
||||||
mPersonalizationHelper.setIsMonolingualUser(isMonolingualUser);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
|
@ -586,9 +571,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mDistracterFilter.close();
|
mDistracterFilter.close();
|
||||||
if (mPersonalizationHelper != null) {
|
|
||||||
mPersonalizationHelper.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedForTesting
|
@UsedForTesting
|
||||||
|
@ -630,20 +612,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushPersonalizationDictionary() {
|
|
||||||
final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion =
|
|
||||||
new HashSet<>();
|
|
||||||
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
|
|
||||||
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
|
|
||||||
final ExpandableBinaryDictionary personalizationDictUsedForSuggestion =
|
|
||||||
dictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION);
|
|
||||||
personalizationDictsUsedForSuggestion.add(personalizationDictUsedForSuggestion);
|
|
||||||
}
|
|
||||||
mPersonalizationHelper.flushPersonalizationDictionariesToUpdate(
|
|
||||||
personalizationDictsUsedForSuggestion);
|
|
||||||
mDistracterFilter.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
|
public void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
|
||||||
throws InterruptedException {
|
throws InterruptedException {
|
||||||
mLatchForWaitingLoadingMainDictionaries.await(timeout, unit);
|
mLatchForWaitingLoadingMainDictionaries.await(timeout, unit);
|
||||||
|
@ -861,64 +829,10 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
||||||
clearSubDictionary(Dictionary.TYPE_USER_HISTORY);
|
clearSubDictionary(Dictionary.TYPE_USER_HISTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called only when the IME receives a notification to remove the
|
|
||||||
// personalization dictionary.
|
|
||||||
public void clearPersonalizationDictionary() {
|
|
||||||
clearSubDictionary(Dictionary.TYPE_PERSONALIZATION);
|
|
||||||
mPersonalizationHelper.clearDictionariesToUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearContextualDictionary() {
|
public void clearContextualDictionary() {
|
||||||
clearSubDictionary(Dictionary.TYPE_CONTEXTUAL);
|
clearSubDictionary(Dictionary.TYPE_CONTEXTUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntriesToPersonalizationDictionary(
|
|
||||||
final PersonalizationDataChunk personalizationDataChunk,
|
|
||||||
final SpacingAndPunctuations spacingAndPunctuations,
|
|
||||||
final UpdateEntriesForInputEventsCallback callback) {
|
|
||||||
mPersonalizationHelper.updateEntriesOfPersonalizationDictionaries(
|
|
||||||
getMostProbableLocale(), personalizationDataChunk, spacingAndPunctuations,
|
|
||||||
callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
public void addPhraseToContextualDictionary(final String[] phrase, final int probability,
|
|
||||||
final int bigramProbabilityForWords, final int bigramProbabilityForPhrases) {
|
|
||||||
// TODO: we're inserting the phrase into the dictionary for the active language. Rethink
|
|
||||||
// this a bit from a theoretical point of view.
|
|
||||||
final ExpandableBinaryDictionary contextualDict =
|
|
||||||
getDictionaryGroupForMostProbableLanguage().getSubDict(Dictionary.TYPE_CONTEXTUAL);
|
|
||||||
if (contextualDict == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NgramContext ngramContext = NgramContext.BEGINNING_OF_SENTENCE;
|
|
||||||
for (int i = 0; i < phrase.length; i++) {
|
|
||||||
final String[] subPhrase = Arrays.copyOfRange(phrase, i /* start */, phrase.length);
|
|
||||||
final String subPhraseStr = TextUtils.join(Constants.WORD_SEPARATOR, subPhrase);
|
|
||||||
contextualDict.addUnigramEntryWithCheckingDistracter(
|
|
||||||
subPhraseStr, probability, null /* shortcutTarget */,
|
|
||||||
Dictionary.NOT_A_PROBABILITY /* shortcutFreq */,
|
|
||||||
false /* isNotAWord */, false /* isPossiblyOffensive */,
|
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP,
|
|
||||||
DistracterFilter.EMPTY_DISTRACTER_FILTER);
|
|
||||||
contextualDict.addNgramEntry(ngramContext, subPhraseStr,
|
|
||||||
bigramProbabilityForPhrases, BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
|
||||||
|
|
||||||
if (i < phrase.length - 1) {
|
|
||||||
contextualDict.addUnigramEntryWithCheckingDistracter(
|
|
||||||
phrase[i], probability, null /* shortcutTarget */,
|
|
||||||
Dictionary.NOT_A_PROBABILITY /* shortcutFreq */,
|
|
||||||
false /* isNotAWord */, false /* isPossiblyOffensive */,
|
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP,
|
|
||||||
DistracterFilter.EMPTY_DISTRACTER_FILTER);
|
|
||||||
contextualDict.addNgramEntry(ngramContext, phrase[i],
|
|
||||||
bigramProbabilityForWords, BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
|
||||||
}
|
|
||||||
ngramContext =
|
|
||||||
ngramContext.getNextNgramContext(new NgramContext.WordInfo(phrase[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dumpDictionaryForDebug(final String dictName) {
|
public void dumpDictionaryForDebug(final String dictName) {
|
||||||
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
|
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
|
||||||
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
|
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
|
||||||
|
|
|
@ -81,9 +81,7 @@ import com.android.inputmethod.latin.common.InputPointers;
|
||||||
import com.android.inputmethod.latin.define.DebugFlags;
|
import com.android.inputmethod.latin.define.DebugFlags;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlags;
|
import com.android.inputmethod.latin.define.ProductionFlags;
|
||||||
import com.android.inputmethod.latin.inputlogic.InputLogic;
|
import com.android.inputmethod.latin.inputlogic.InputLogic;
|
||||||
import com.android.inputmethod.latin.personalization.ContextualDictionaryUpdater;
|
|
||||||
import com.android.inputmethod.latin.personalization.DictionaryDecayBroadcastReciever;
|
import com.android.inputmethod.latin.personalization.DictionaryDecayBroadcastReciever;
|
||||||
import com.android.inputmethod.latin.personalization.PersonalizationDictionaryUpdater;
|
|
||||||
import com.android.inputmethod.latin.personalization.PersonalizationHelper;
|
import com.android.inputmethod.latin.personalization.PersonalizationHelper;
|
||||||
import com.android.inputmethod.latin.settings.Settings;
|
import com.android.inputmethod.latin.settings.Settings;
|
||||||
import com.android.inputmethod.latin.settings.SettingsActivity;
|
import com.android.inputmethod.latin.settings.SettingsActivity;
|
||||||
|
@ -139,19 +137,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
private static final String SCHEME_PACKAGE = "package";
|
private static final String SCHEME_PACKAGE = "package";
|
||||||
|
|
||||||
final Settings mSettings;
|
final Settings mSettings;
|
||||||
private final DictionaryFacilitator mDictionaryFacilitator =
|
private final DictionaryFacilitator mDictionaryFacilitator =
|
||||||
DictionaryFacilitatorProvider.newDictionaryFacilitator(this /* context */);
|
DictionaryFacilitatorProvider.newDictionaryFacilitator(this /* context */);
|
||||||
// TODO: Move from LatinIME.
|
|
||||||
private final PersonalizationDictionaryUpdater mPersonalizationDictionaryUpdater =
|
|
||||||
new PersonalizationDictionaryUpdater(this /* context */, mDictionaryFacilitator);
|
|
||||||
private final ContextualDictionaryUpdater mContextualDictionaryUpdater =
|
|
||||||
new ContextualDictionaryUpdater(this /* context */, mDictionaryFacilitator,
|
|
||||||
new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mHandler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
final InputLogic mInputLogic = new InputLogic(this /* LatinIME */,
|
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.
|
||||||
|
@ -642,11 +629,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
|
|
||||||
private void refreshPersonalizationDictionarySession(
|
private void refreshPersonalizationDictionarySession(
|
||||||
final SettingsValues currentSettingsValues) {
|
final SettingsValues currentSettingsValues) {
|
||||||
|
// TODO: Remove all existing personalized dictionaries.
|
||||||
mDictionaryFacilitator.setIsMonolingualUser(
|
mDictionaryFacilitator.setIsMonolingualUser(
|
||||||
mRichImm.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes());
|
mRichImm.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes());
|
||||||
mPersonalizationDictionaryUpdater.onLoadSettings(
|
|
||||||
currentSettingsValues.mUsePersonalizedDicts);
|
|
||||||
mContextualDictionaryUpdater.onLoadSettings(currentSettingsValues.mUsePersonalizedDicts);
|
|
||||||
final boolean shouldKeepUserHistoryDictionaries;
|
final boolean shouldKeepUserHistoryDictionaries;
|
||||||
if (currentSettingsValues.mUsePersonalizedDicts) {
|
if (currentSettingsValues.mUsePersonalizedDicts) {
|
||||||
shouldKeepUserHistoryDictionaries = true;
|
shouldKeepUserHistoryDictionaries = true;
|
||||||
|
@ -730,8 +715,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
mDictionaryFacilitator.closeDictionaries();
|
mDictionaryFacilitator.closeDictionaries();
|
||||||
mPersonalizationDictionaryUpdater.onDestroy();
|
|
||||||
mContextualDictionaryUpdater.onDestroy();
|
|
||||||
mSettings.onDestroy();
|
mSettings.onDestroy();
|
||||||
NetworkConnectivityUtils.onDestroy(this /* context */);
|
NetworkConnectivityUtils.onDestroy(this /* context */);
|
||||||
unregisterReceiver(mRingerModeChangeReceiver);
|
unregisterReceiver(mRingerModeChangeReceiver);
|
||||||
|
@ -1050,8 +1033,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
currentSettingsValues.mGestureTrailEnabled,
|
currentSettingsValues.mGestureTrailEnabled,
|
||||||
currentSettingsValues.mGestureFloatingPreviewTextEnabled);
|
currentSettingsValues.mGestureFloatingPreviewTextEnabled);
|
||||||
|
|
||||||
// Contextual dictionary should be updated for the current application.
|
|
||||||
mContextualDictionaryUpdater.onStartInputView(editorInfo.packageName);
|
|
||||||
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
|
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1943,7 +1924,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
@UsedForTesting
|
@UsedForTesting
|
||||||
/* package for test */ void clearPersonalizedDictionariesForTest() {
|
/* package for test */ void clearPersonalizedDictionariesForTest() {
|
||||||
mDictionaryFacilitator.clearUserHistoryDictionary();
|
mDictionaryFacilitator.clearUserHistoryDictionary();
|
||||||
mDictionaryFacilitator.clearPersonalizationDictionary();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedForTesting
|
@UsedForTesting
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback;
|
|
||||||
import com.android.inputmethod.latin.personalization.PersonalizationDataChunk;
|
|
||||||
import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
|
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
|
||||||
import com.android.inputmethod.latin.utils.DistracterFilter;
|
|
||||||
import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary;
|
|
||||||
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
|
||||||
import com.android.inputmethod.latin.utils.WordInputEventForPersonalization;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class for managing and updating personalization dictionaries.
|
|
||||||
*/
|
|
||||||
public class PersonalizationHelperForDictionaryFacilitator {
|
|
||||||
private final Context mContext;
|
|
||||||
private final DistracterFilter mDistracterFilter;
|
|
||||||
private final HashMap<String, HashSet<Locale>> mLangToLocalesMap = new HashMap<>();
|
|
||||||
private final HashMap<Locale, ExpandableBinaryDictionary> mPersonalizationDictsToUpdate =
|
|
||||||
new HashMap<>();
|
|
||||||
private boolean mIsMonolingualUser = false;
|
|
||||||
|
|
||||||
PersonalizationHelperForDictionaryFacilitator(final Context context,
|
|
||||||
final DistracterFilter distracterFilter) {
|
|
||||||
mContext = context;
|
|
||||||
mDistracterFilter = distracterFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
mLangToLocalesMap.clear();
|
|
||||||
for (final ExpandableBinaryDictionary dict : mPersonalizationDictsToUpdate.values()) {
|
|
||||||
dict.close();
|
|
||||||
}
|
|
||||||
mPersonalizationDictsToUpdate.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearDictionariesToUpdate() {
|
|
||||||
for (final ExpandableBinaryDictionary dict : mPersonalizationDictsToUpdate.values()) {
|
|
||||||
dict.clear();
|
|
||||||
}
|
|
||||||
mPersonalizationDictsToUpdate.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
|
|
||||||
for (final InputMethodSubtype subtype : enabledSubtypes) {
|
|
||||||
final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
|
|
||||||
final String language = locale.getLanguage();
|
|
||||||
final HashSet<Locale> locales = mLangToLocalesMap.get(language);
|
|
||||||
if (locales != null) {
|
|
||||||
locales.add(locale);
|
|
||||||
} else {
|
|
||||||
final HashSet<Locale> localeSet = new HashSet<>();
|
|
||||||
localeSet.add(locale);
|
|
||||||
mLangToLocalesMap.put(language, localeSet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsMonolingualUser(final boolean isMonolingualUser) {
|
|
||||||
mIsMonolingualUser = isMonolingualUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush personalization dictionaries to dictionary files. Close dictionaries after writing
|
|
||||||
* files except the dictionaries that is used for generating suggestions.
|
|
||||||
*
|
|
||||||
* @param personalizationDictsUsedForSuggestion the personalization dictionaries used for
|
|
||||||
* generating suggestions that won't be closed.
|
|
||||||
*/
|
|
||||||
public void flushPersonalizationDictionariesToUpdate(
|
|
||||||
final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion) {
|
|
||||||
for (final ExpandableBinaryDictionary personalizationDict :
|
|
||||||
mPersonalizationDictsToUpdate.values()) {
|
|
||||||
personalizationDict.asyncFlushBinaryDictionary();
|
|
||||||
if (!personalizationDictsUsedForSuggestion.contains(personalizationDict)) {
|
|
||||||
// Close if the dictionary is not being used for suggestion.
|
|
||||||
personalizationDict.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mDistracterFilter.close();
|
|
||||||
mPersonalizationDictsToUpdate.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ExpandableBinaryDictionary getPersonalizationDictToUpdate(final Context context,
|
|
||||||
final Locale locale) {
|
|
||||||
ExpandableBinaryDictionary personalizationDict = mPersonalizationDictsToUpdate.get(locale);
|
|
||||||
if (personalizationDict != null) {
|
|
||||||
return personalizationDict;
|
|
||||||
}
|
|
||||||
personalizationDict = PersonalizationDictionary.getDictionary(context, locale,
|
|
||||||
null /* dictFile */, "" /* dictNamePrefix */, null /* account */);
|
|
||||||
mPersonalizationDictsToUpdate.put(locale, personalizationDict);
|
|
||||||
return personalizationDict;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEntriesOfPersonalizationDictionariesForLocale(final Locale locale,
|
|
||||||
final PersonalizationDataChunk personalizationDataChunk,
|
|
||||||
final SpacingAndPunctuations spacingAndPunctuations,
|
|
||||||
final UpdateEntriesForInputEventsCallback callback) {
|
|
||||||
final ExpandableBinaryDictionary personalizationDict =
|
|
||||||
getPersonalizationDictToUpdate(mContext, locale);
|
|
||||||
if (personalizationDict == null) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFinished();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ArrayList<WordInputEventForPersonalization> inputEvents =
|
|
||||||
WordInputEventForPersonalization.createInputEventFrom(
|
|
||||||
personalizationDataChunk.mTokens,
|
|
||||||
personalizationDataChunk.mTimestampInSeconds, spacingAndPunctuations,
|
|
||||||
locale, new DistracterFilterCheckingIsInDictionary(
|
|
||||||
mDistracterFilter, personalizationDict));
|
|
||||||
if (inputEvents == null || inputEvents.isEmpty()) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFinished();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
personalizationDict.updateEntriesForInputEvents(inputEvents, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateEntriesOfPersonalizationDictionaries(final Locale defaultLocale,
|
|
||||||
final PersonalizationDataChunk personalizationDataChunk,
|
|
||||||
final SpacingAndPunctuations spacingAndPunctuations,
|
|
||||||
final UpdateEntriesForInputEventsCallback callback) {
|
|
||||||
final String language = personalizationDataChunk.mDetectedLanguage;
|
|
||||||
final HashSet<Locale> locales;
|
|
||||||
if (mIsMonolingualUser && PersonalizationDataChunk.LANGUAGE_UNKNOWN.equals(language)
|
|
||||||
&& mLangToLocalesMap.size() == 1) {
|
|
||||||
locales = mLangToLocalesMap.get(defaultLocale.getLanguage());
|
|
||||||
} else {
|
|
||||||
locales = mLangToLocalesMap.get(language);
|
|
||||||
}
|
|
||||||
if (locales == null || locales.isEmpty()) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFinished();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final AtomicInteger remainingTaskCount = new AtomicInteger(locales.size());
|
|
||||||
final UpdateEntriesForInputEventsCallback callbackForLocales =
|
|
||||||
new UpdateEntriesForInputEventsCallback() {
|
|
||||||
@Override
|
|
||||||
public void onFinished() {
|
|
||||||
if (remainingTaskCount.decrementAndGet() == 0) {
|
|
||||||
// Update tasks for all locales have been finished.
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for (final Locale locale : locales) {
|
|
||||||
updateEntriesOfPersonalizationDictionariesForLocale(locale, personalizationDataChunk,
|
|
||||||
spacingAndPunctuations, callbackForLocales);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 android.content.Context;
|
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.ExternallyReferenced;
|
|
||||||
import com.android.inputmethod.latin.Dictionary;
|
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
private ContextualDictionary(final Context context, final Locale locale,
|
|
||||||
final File dictFile) {
|
|
||||||
super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_CONTEXTUAL,
|
|
||||||
dictFile);
|
|
||||||
// Always reset the contents.
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ExternallyReferenced
|
|
||||||
public static ContextualDictionary getDictionary(final Context context, final Locale locale,
|
|
||||||
final File dictFile, final String dictNamePrefix, @Nullable final String account) {
|
|
||||||
return new ContextualDictionary(context, locale, dictFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValidWord(final String word) {
|
|
||||||
// Strings out of this dictionary should not be considered existing words.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void loadInitialContentsLocked() {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -84,7 +84,6 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) {
|
if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) {
|
||||||
PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries();
|
PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries();
|
||||||
PersonalizationHelper.runGCOnAllOpenedPersonalizationDictionaries();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
public class PersonalizationDataChunk {
|
|
||||||
public static final String LANGUAGE_UNKNOWN = "";
|
|
||||||
|
|
||||||
public final boolean mInputByUser;
|
|
||||||
public final List<String> mTokens;
|
|
||||||
public final int mTimestampInSeconds;
|
|
||||||
public final String mPackageName;
|
|
||||||
public final String mDetectedLanguage;
|
|
||||||
|
|
||||||
public PersonalizationDataChunk(boolean inputByUser, final List<String> tokens,
|
|
||||||
final int timestampInSeconds, final String packageName, final String detectedLanguage) {
|
|
||||||
mInputByUser = inputByUser;
|
|
||||||
mTokens = Collections.unmodifiableList(tokens);
|
|
||||||
mTimestampInSeconds = timestampInSeconds;
|
|
||||||
mPackageName = packageName;
|
|
||||||
mDetectedLanguage = detectedLanguage;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 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 android.content.Context;
|
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.ExternallyReferenced;
|
|
||||||
import com.android.inputmethod.latin.Dictionary;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
// TODO: Make this constructor private
|
|
||||||
/* package */ PersonalizationDictionary(final Context context, final Locale locale) {
|
|
||||||
super(context, getDictName(NAME, locale, null /* dictFile */), locale,
|
|
||||||
Dictionary.TYPE_PERSONALIZATION, null /* dictFile */);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ExternallyReferenced
|
|
||||||
public static PersonalizationDictionary getDictionary(final Context context,
|
|
||||||
final Locale locale, final File dictFile, final String dictNamePrefix,
|
|
||||||
@Nullable final String account) {
|
|
||||||
return PersonalizationHelper.getPersonalizationDictionary(context, locale);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -32,8 +32,7 @@ import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary} and
|
* Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary}.
|
||||||
* {@link PersonalizationDictionary}.
|
|
||||||
*/
|
*/
|
||||||
public class PersonalizationHelper {
|
public class PersonalizationHelper {
|
||||||
private static final String TAG = PersonalizationHelper.class.getSimpleName();
|
private static final String TAG = PersonalizationHelper.class.getSimpleName();
|
||||||
|
@ -41,8 +40,6 @@ public class PersonalizationHelper {
|
||||||
|
|
||||||
private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
|
private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
|
||||||
sLangUserHistoryDictCache = new ConcurrentHashMap<>();
|
sLangUserHistoryDictCache = new ConcurrentHashMap<>();
|
||||||
private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>>
|
|
||||||
sLangPersonalizationDictCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static UserHistoryDictionary getUserHistoryDictionary(
|
public static UserHistoryDictionary getUserHistoryDictionary(
|
||||||
|
@ -77,7 +74,6 @@ public class PersonalizationHelper {
|
||||||
DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL_IN_MILLIS)
|
DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL_IN_MILLIS)
|
||||||
< currentTimestamp - sCurrentTimestampForTesting) {
|
< currentTimestamp - sCurrentTimestampForTesting) {
|
||||||
runGCOnAllOpenedUserHistoryDictionaries();
|
runGCOnAllOpenedUserHistoryDictionaries();
|
||||||
runGCOnAllOpenedPersonalizationDictionaries();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,10 +81,6 @@ public class PersonalizationHelper {
|
||||||
runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache);
|
runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void runGCOnAllOpenedPersonalizationDictionaries() {
|
|
||||||
runGCOnAllDictionariesIfRequired(sLangPersonalizationDictCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends DecayingExpandableBinaryDictionaryBase>
|
private static <T extends DecayingExpandableBinaryDictionaryBase>
|
||||||
void runGCOnAllDictionariesIfRequired(
|
void runGCOnAllDictionariesIfRequired(
|
||||||
final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) {
|
final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) {
|
||||||
|
@ -103,32 +95,6 @@ public class PersonalizationHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PersonalizationDictionary getPersonalizationDictionary(
|
|
||||||
final Context context, final Locale locale) {
|
|
||||||
final String localeStr = locale.toString();
|
|
||||||
synchronized (sLangPersonalizationDictCache) {
|
|
||||||
if (sLangPersonalizationDictCache.containsKey(localeStr)) {
|
|
||||||
final SoftReference<PersonalizationDictionary> ref =
|
|
||||||
sLangPersonalizationDictCache.get(localeStr);
|
|
||||||
final PersonalizationDictionary dict = ref == null ? null : ref.get();
|
|
||||||
if (dict != null) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Use cached PersonalizationDictionary for " + locale);
|
|
||||||
}
|
|
||||||
return dict;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final PersonalizationDictionary dict = new PersonalizationDictionary(context, locale);
|
|
||||||
sLangPersonalizationDictCache.put(localeStr, new SoftReference<>(dict));
|
|
||||||
return dict;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeAllPersonalizationDictionaries(final Context context) {
|
|
||||||
removeAllDictionaries(context, sLangPersonalizationDictCache,
|
|
||||||
PersonalizationDictionary.NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeAllUserHistoryDictionaries(final Context context) {
|
public static void removeAllUserHistoryDictionaries(final Context context) {
|
||||||
removeAllDictionaries(context, sLangUserHistoryDictCache,
|
removeAllDictionaries(context, sLangUserHistoryDictCache,
|
||||||
UserHistoryDictionary.NAME);
|
UserHistoryDictionary.NAME);
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.Dictionary;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitator;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitatorProvider;
|
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary;
|
|
||||||
|
|
||||||
import android.test.AndroidTestCase;
|
|
||||||
import android.test.suitebuilder.annotation.LargeTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit tests for contextual dictionary
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public class ContextualDictionaryTests extends AndroidTestCase {
|
|
||||||
private static final Locale LOCALE_EN_US = new Locale("en", "US");
|
|
||||||
|
|
||||||
private DictionaryFacilitator getDictionaryFacilitator() {
|
|
||||||
final ArrayList<String> dictTypes = new ArrayList<>();
|
|
||||||
dictTypes.add(Dictionary.TYPE_CONTEXTUAL);
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator =
|
|
||||||
DictionaryFacilitatorProvider.newDictionaryFacilitator();
|
|
||||||
dictionaryFacilitator.resetDictionariesForTesting(getContext(),
|
|
||||||
new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(),
|
|
||||||
Collections.<String, Map<String, String>>emptyMap(), null /* account */);
|
|
||||||
return dictionaryFacilitator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAddPhrase() {
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator = getDictionaryFacilitator();
|
|
||||||
final String[] phrase = new String[] {"a", "b", "c", "d"};
|
|
||||||
final int probability = 100;
|
|
||||||
final int bigramProbabilityForWords = 150;
|
|
||||||
final int bigramProbabilityForPhrases = 200;
|
|
||||||
dictionaryFacilitator.addPhraseToContextualDictionary(
|
|
||||||
phrase, probability, bigramProbabilityForWords, bigramProbabilityForPhrases);
|
|
||||||
final ExpandableBinaryDictionary contextualDictionary =
|
|
||||||
dictionaryFacilitator.getSubDictForTesting(Dictionary.TYPE_CONTEXTUAL);
|
|
||||||
contextualDictionary.waitAllTasksForTests();
|
|
||||||
// Word
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("a"));
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("b"));
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("c"));
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("d"));
|
|
||||||
// Phrase
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("a b c d"));
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("b c d"));
|
|
||||||
assertTrue(contextualDictionary.isInDictionary("c d"));
|
|
||||||
assertFalse(contextualDictionary.isInDictionary("a b c"));
|
|
||||||
assertFalse(contextualDictionary.isInDictionary("abcd"));
|
|
||||||
// TODO: Add tests for probability.
|
|
||||||
// TODO: Add tests for n-grams.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.BinaryDictionary;
|
|
||||||
import com.android.inputmethod.latin.Dictionary;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitator;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFacilitatorProvider;
|
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary;
|
|
||||||
import com.android.inputmethod.latin.RichInputMethodManager;
|
|
||||||
import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback;
|
|
||||||
import com.android.inputmethod.latin.common.CodePointUtils;
|
|
||||||
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
|
|
||||||
|
|
||||||
import android.test.AndroidTestCase;
|
|
||||||
import android.test.suitebuilder.annotation.LargeTest;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit tests for personalization dictionary
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public class PersonalizationDictionaryTests extends AndroidTestCase {
|
|
||||||
private static final String TAG = PersonalizationDictionaryTests.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final Locale LOCALE_EN_US = new Locale("en", "US");
|
|
||||||
private static final String DUMMY_PACKAGE_NAME = "test.package.name";
|
|
||||||
private static final long TIMEOUT_TO_WAIT_DICTIONARY_OPERATIONS_IN_SECONDS = 120;
|
|
||||||
|
|
||||||
private DictionaryFacilitator getDictionaryFacilitator() {
|
|
||||||
final ArrayList<String> dictTypes = new ArrayList<>();
|
|
||||||
dictTypes.add(Dictionary.TYPE_MAIN);
|
|
||||||
dictTypes.add(Dictionary.TYPE_PERSONALIZATION);
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator =
|
|
||||||
DictionaryFacilitatorProvider.newDictionaryFacilitator(getContext());
|
|
||||||
dictionaryFacilitator.resetDictionariesForTesting(getContext(),
|
|
||||||
new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(),
|
|
||||||
Collections.<String, Map<String, String>>emptyMap(), null /* account */);
|
|
||||||
// Set subtypes.
|
|
||||||
RichInputMethodManager.init(getContext());
|
|
||||||
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
|
|
||||||
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
|
|
||||||
subtypes.add(richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
|
|
||||||
LOCALE_EN_US.toString(), "qwerty"));
|
|
||||||
dictionaryFacilitator.updateEnabledSubtypes(subtypes);
|
|
||||||
return dictionaryFacilitator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAddManyTokens() {
|
|
||||||
final DictionaryFacilitator dictionaryFacilitator = getDictionaryFacilitator();
|
|
||||||
dictionaryFacilitator.clearPersonalizationDictionary();
|
|
||||||
final int dataChunkCount = 100;
|
|
||||||
final int wordCountInOneChunk = 200;
|
|
||||||
final int uniqueWordCount = 100;
|
|
||||||
final Random random = new Random(System.currentTimeMillis());
|
|
||||||
final int[] codePointSet = CodePointUtils.LATIN_ALPHABETS_LOWER;
|
|
||||||
final ArrayList<String> words = new ArrayList<>();
|
|
||||||
for (int i = 0; i < uniqueWordCount; i++) {
|
|
||||||
words.add(CodePointUtils.generateWord(random, codePointSet));
|
|
||||||
}
|
|
||||||
|
|
||||||
final SpacingAndPunctuations spacingAndPunctuations =
|
|
||||||
new SpacingAndPunctuations(getContext().getResources());
|
|
||||||
|
|
||||||
final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds(
|
|
||||||
System.currentTimeMillis());
|
|
||||||
|
|
||||||
for (int i = 0; i < dataChunkCount; i++) {
|
|
||||||
final ArrayList<String> tokens = new ArrayList<>();
|
|
||||||
for (int j = 0; j < wordCountInOneChunk; j++) {
|
|
||||||
tokens.add(words.get(random.nextInt(words.size())));
|
|
||||||
}
|
|
||||||
final PersonalizationDataChunk personalizationDataChunk = new PersonalizationDataChunk(
|
|
||||||
true /* inputByUser */, tokens, timeStampInSeconds, DUMMY_PACKAGE_NAME,
|
|
||||||
LOCALE_EN_US.getLanguage());
|
|
||||||
final CountDownLatch countDownLatch = new CountDownLatch(1);
|
|
||||||
final UpdateEntriesForInputEventsCallback callback =
|
|
||||||
new UpdateEntriesForInputEventsCallback() {
|
|
||||||
@Override
|
|
||||||
public void onFinished() {
|
|
||||||
countDownLatch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
dictionaryFacilitator.addEntriesToPersonalizationDictionary(personalizationDataChunk,
|
|
||||||
spacingAndPunctuations, callback);
|
|
||||||
try {
|
|
||||||
countDownLatch.await(TIMEOUT_TO_WAIT_DICTIONARY_OPERATIONS_IN_SECONDS,
|
|
||||||
TimeUnit.SECONDS);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(TAG, "Interrupted while waiting for finishing dictionary operations.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dictionaryFacilitator.flushPersonalizationDictionary();
|
|
||||||
try {
|
|
||||||
dictionaryFacilitator.waitForLoadingDictionariesForTesting(
|
|
||||||
TIMEOUT_TO_WAIT_DICTIONARY_OPERATIONS_IN_SECONDS, TimeUnit.SECONDS);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(TAG, "Interrupted while waiting for finishing dictionary operations.", e);
|
|
||||||
}
|
|
||||||
final String dictName = ExpandableBinaryDictionary.getDictName(
|
|
||||||
PersonalizationDictionary.NAME, LOCALE_EN_US, null /* dictFile */);
|
|
||||||
final File dictFile = ExpandableBinaryDictionary.getDictFile(
|
|
||||||
getContext(), dictName, null /* dictFile */);
|
|
||||||
|
|
||||||
final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
|
|
||||||
0 /* offset */, 0 /* size */,
|
|
||||||
true /* useFullEditDistance */, LOCALE_EN_US, Dictionary.TYPE_PERSONALIZATION,
|
|
||||||
true /* isUpdatable */);
|
|
||||||
assertTrue(binaryDictionary.isValidDictionary());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue