futokb/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
Jatin Matani bc4ae6bdc0 Passing account info to dictionaryFacilitator
Attempt to use dictionary facilitor without invoking
preference manager. Instead use account from settings only when
things are being reset/changed. Discussion forked from ag/591663

Overall, the idea here is to maintain an account information
inside dictionary groups. Reset the dictionary groups if
account changes (the way we do for locale). Since only user
history dictionary is currently affected, the check to reset user
history dictionary also includes the check to verify the account.
For other things remain the same.

SettingsValues holds the current account (and is updated if prefs change
due to change in account settings). The updated settings are then
propagated to dictionary facilitator via LatinIME#loadSettings.

Bug:18104749,18469539
Change-Id: I553e776e7ea125d0fb7a1fe70a4c7eb0b2277fb8
2014-12-16 15:56:00 -08:00

186 lines
8.0 KiB
Java

/*
* 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);
}
}
}