Merge "Nuke Amanatto"

This commit is contained in:
Jatin Matani 2015-02-03 19:20:39 +00:00 committed by Android (Google) Code Review
commit 48cc0d6420
13 changed files with 5 additions and 791 deletions

View file

@ -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() {
}
}

View file

@ -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() {
}
}

View file

@ -17,21 +17,18 @@
package com.android.inputmethod.latin;
import android.content.Context;
import android.view.inputmethod.InputMethodSubtype;
import android.util.Pair;
import android.view.inputmethod.InputMethodSubtype;
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.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.SuggestionResults;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -120,8 +117,6 @@ public interface DictionaryFacilitator {
boolean hasPersonalizationDictionary();
void flushPersonalizationDictionary();
void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
throws InterruptedException;
@ -152,21 +147,6 @@ public interface DictionaryFacilitator {
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);
ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts();

View file

@ -23,16 +23,11 @@ import android.util.Pair;
import android.view.inputmethod.InputMethodSubtype;
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.SuggestedWords.SuggestedWordInfo;
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.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.DistracterFilter;
import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary;
@ -83,16 +78,13 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
// To synchronize assigning mDictionaryGroup to ensure closing dictionaries.
private final Object mLock = new Object();
private final DistracterFilter mDistracterFilter;
private final PersonalizationHelperForDictionaryFacilitator mPersonalizationHelper;
private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS =
new String[] {
Dictionary.TYPE_MAIN,
Dictionary.TYPE_USER_HISTORY,
Dictionary.TYPE_PERSONALIZATION,
Dictionary.TYPE_USER,
Dictionary.TYPE_CONTACTS,
Dictionary.TYPE_CONTEXTUAL
};
public static final Map<String, Class<? extends ExpandableBinaryDictionary>>
@ -100,10 +92,8 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
static {
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_CONTACTS, ContactsBinaryDictionary.class);
DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTEXTUAL, ContextualDictionary.class);
}
private static final String DICT_FACTORY_METHOD_NAME = "getDictionary";
@ -257,23 +247,18 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
public DictionaryFacilitatorImpl() {
mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER;
mPersonalizationHelper = null;
}
public DictionaryFacilitatorImpl(final Context context) {
mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context);
mPersonalizationHelper =
new PersonalizationHelperForDictionaryFacilitator(context, mDistracterFilter);
}
public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
mDistracterFilter.updateEnabledSubtypes(enabledSubtypes);
mPersonalizationHelper.updateEnabledSubtypes(enabledSubtypes);
}
// TODO: remove this, it's confusing with seamless multiple language switching
public void setIsMonolingualUser(final boolean isMonolingualUser) {
mPersonalizationHelper.setIsMonolingualUser(isMonolingualUser);
}
public boolean isActive() {
@ -586,9 +571,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
}
}
mDistracterFilter.close();
if (mPersonalizationHelper != null) {
mPersonalizationHelper.close();
}
}
@UsedForTesting
@ -630,20 +612,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
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)
throws InterruptedException {
mLatchForWaitingLoadingMainDictionaries.await(timeout, unit);
@ -861,64 +829,10 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
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() {
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) {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {

View file

@ -81,9 +81,7 @@ import com.android.inputmethod.latin.common.InputPointers;
import com.android.inputmethod.latin.define.DebugFlags;
import com.android.inputmethod.latin.define.ProductionFlags;
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.PersonalizationDictionaryUpdater;
import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.settings.SettingsActivity;
@ -141,17 +139,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Settings mSettings;
private final DictionaryFacilitator mDictionaryFacilitator =
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 */,
this /* SuggestionStripViewAccessor */, mDictionaryFacilitator);
// 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(
final SettingsValues currentSettingsValues) {
// TODO: Remove all existing personalized dictionaries.
mDictionaryFacilitator.setIsMonolingualUser(
mRichImm.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes());
mPersonalizationDictionaryUpdater.onLoadSettings(
currentSettingsValues.mUsePersonalizedDicts);
mContextualDictionaryUpdater.onLoadSettings(currentSettingsValues.mUsePersonalizedDicts);
final boolean shouldKeepUserHistoryDictionaries;
if (currentSettingsValues.mUsePersonalizedDicts) {
shouldKeepUserHistoryDictionaries = true;
@ -730,8 +715,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onDestroy() {
mDictionaryFacilitator.closeDictionaries();
mPersonalizationDictionaryUpdater.onDestroy();
mContextualDictionaryUpdater.onDestroy();
mSettings.onDestroy();
NetworkConnectivityUtils.onDestroy(this /* context */);
unregisterReceiver(mRingerModeChangeReceiver);
@ -1050,8 +1033,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
currentSettingsValues.mGestureTrailEnabled,
currentSettingsValues.mGestureFloatingPreviewTextEnabled);
// Contextual dictionary should be updated for the current application.
mContextualDictionaryUpdater.onStartInputView(editorInfo.packageName);
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
}
@ -1943,7 +1924,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@UsedForTesting
/* package for test */ void clearPersonalizedDictionariesForTest() {
mDictionaryFacilitator.clearUserHistoryDictionary();
mDictionaryFacilitator.clearPersonalizationDictionary();
}
@UsedForTesting

View file

@ -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);
}
}
}

View file

@ -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() {
}
}

View file

@ -84,7 +84,6 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver {
final String action = intent.getAction();
if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) {
PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries();
PersonalizationHelper.runGCOnAllOpenedPersonalizationDictionaries();
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -32,8 +32,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary} and
* {@link PersonalizationDictionary}.
* Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary}.
*/
public class PersonalizationHelper {
private static final String TAG = PersonalizationHelper.class.getSimpleName();
@ -41,8 +40,6 @@ public class PersonalizationHelper {
private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
sLangUserHistoryDictCache = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>>
sLangPersonalizationDictCache = new ConcurrentHashMap<>();
@Nonnull
public static UserHistoryDictionary getUserHistoryDictionary(
@ -77,7 +74,6 @@ public class PersonalizationHelper {
DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL_IN_MILLIS)
< currentTimestamp - sCurrentTimestampForTesting) {
runGCOnAllOpenedUserHistoryDictionaries();
runGCOnAllOpenedPersonalizationDictionaries();
}
}
@ -85,10 +81,6 @@ public class PersonalizationHelper {
runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache);
}
public static void runGCOnAllOpenedPersonalizationDictionaries() {
runGCOnAllDictionariesIfRequired(sLangPersonalizationDictCache);
}
private static <T extends DecayingExpandableBinaryDictionaryBase>
void runGCOnAllDictionariesIfRequired(
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) {
removeAllDictionaries(context, sLangUserHistoryDictCache,
UserHistoryDictionary.NAME);

View file

@ -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.
}
}

View file

@ -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());
}
}