diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
14 files changed, 189 insertions, 172 deletions
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 59763c0fc..22fd90795 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -39,6 +39,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import javax.annotation.Nullable; + public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME}; @@ -86,7 +88,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. @ExternallyReferenced public static ContactsBinaryDictionary getDictionary(final Context context, final Locale locale, - final File dictFile, final String dictNamePrefix) { + final File dictFile, final String dictNamePrefix, @Nullable final String account) { return new ContactsBinaryDictionary(context, locale, dictFile, dictNamePrefix + NAME); } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index acf9cf10c..b8893a5d8 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -44,6 +44,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -56,8 +57,16 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import javax.annotation.Nullable; -// TODO: Consolidate dictionaries in native code. +/** + * Facilitates interaction with different kinds of dictionaries. Provides APIs + * to instantiate and select the correct dictionaries (based on language or account), + * update entries and fetch suggestions. + * + * Currently AndroidSpellCheckerService and LatinIME both use DictionaryFacilitator as + * a client for interacting with dictionaries. + */ public class DictionaryFacilitator { + // TODO: Consolidate dictionaries in native code. public static final String TAG = DictionaryFacilitator.class.getSimpleName(); // HACK: This threshold is being used when adding a capitalized entry in the User History @@ -99,7 +108,7 @@ public class DictionaryFacilitator { private static final String DICT_FACTORY_METHOD_NAME = "getDictionary"; private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES = - new Class[] { Context.class, Locale.class, File.class, String.class }; + new Class[] { Context.class, Locale.class, File.class, String.class, String.class }; private static final String[] SUB_DICT_TYPES = Arrays.copyOfRange(DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS, 1 /* start */, @@ -107,8 +116,8 @@ public class DictionaryFacilitator { /** * Returns whether this facilitator is exactly for this list of locales. + * * @param locales the list of locales to test against - * @return true if this facilitator handles exactly this list of locales, false otherwise */ public boolean isForLocales(final Locale[] locales) { if (locales.length != mDictionaryGroups.length) { @@ -130,33 +139,62 @@ public class DictionaryFacilitator { } /** + * Returns whether this facilitator is exactly for this account. + * + * @param account the account to test against. + */ + public boolean isForAccount(@Nullable final String account) { + for (final DictionaryGroup group : mDictionaryGroups) { + if (!TextUtils.equals(group.mAccount, account)) { + return false; + } + } + return true; + } + + /** * A group of dictionaries that work together for a single language. */ private static class DictionaryGroup { + // TODO: Add null analysis annotations. // TODO: Run evaluation to determine a reasonable value for these constants. The current // values are ad-hoc and chosen without any particular care or methodology. public static final float WEIGHT_FOR_MOST_PROBABLE_LANGUAGE = 1.0f; public static final float WEIGHT_FOR_GESTURING_IN_NOT_MOST_PROBABLE_LANGUAGE = 0.95f; public static final float WEIGHT_FOR_TYPING_IN_NOT_MOST_PROBABLE_LANGUAGE = 0.6f; - public final Locale mLocale; - private Dictionary mMainDict; + /** + * The locale associated with the dictionary group. + */ + @Nullable public final Locale mLocale; + + /** + * The user account associated with the dictionary group. + */ + @Nullable public final String mAccount; + + @Nullable private Dictionary mMainDict; // Confidence that the most probable language is actually the language the user is // typing in. For now, this is simply the number of times a word from this language // has been committed in a row. private int mConfidence = 0; + public float mWeightForTypingInLocale = WEIGHT_FOR_MOST_PROBABLE_LANGUAGE; public float mWeightForGesturingInLocale = WEIGHT_FOR_MOST_PROBABLE_LANGUAGE; public final ConcurrentHashMap<String, ExpandableBinaryDictionary> mSubDictMap = new ConcurrentHashMap<>(); public DictionaryGroup() { - mLocale = null; + this(null /* locale */, null /* mainDict */, null /* account */, + Collections.<String, ExpandableBinaryDictionary>emptyMap() /* subDicts */); } - public DictionaryGroup(final Locale locale, final Dictionary mainDict, + public DictionaryGroup(@Nullable final Locale locale, + @Nullable final Dictionary mainDict, + @Nullable final String account, final Map<String, ExpandableBinaryDictionary> subDicts) { mLocale = locale; + mAccount = account; // The main dictionary can be asynchronously loaded. setMainDict(mainDict); for (final Map.Entry<String, ExpandableBinaryDictionary> entry : subDicts.entrySet()) { @@ -190,10 +228,17 @@ public class DictionaryFacilitator { return mSubDictMap.get(dictType); } - public boolean hasDict(final String dictType) { + public boolean hasDict(final String dictType, @Nullable final String account) { if (Dictionary.TYPE_MAIN.equals(dictType)) { return mMainDict != null; } + if (Dictionary.TYPE_USER_HISTORY.equals(dictType) && + !TextUtils.equals(account, mAccount)) { + // If the dictionary type is user history, & if the account doesn't match, + // return immediately. If the account matches, continue looking it up in the + // sub dictionary map. + return false; + } return mSubDictMap.containsKey(dictType); } @@ -310,7 +355,7 @@ public class DictionaryFacilitator { @Nullable private static ExpandableBinaryDictionary getSubDict(final String dictType, final Context context, final Locale locale, final File dictFile, - final String dictNamePrefix) { + final String dictNamePrefix, @Nullable final String account) { final Class<? extends ExpandableBinaryDictionary> dictClass = DICT_TYPE_TO_CLASS.get(dictType); if (dictClass == null) { @@ -320,7 +365,7 @@ public class DictionaryFacilitator { final Method factoryMethod = dictClass.getMethod(DICT_FACTORY_METHOD_NAME, DICT_FACTORY_METHOD_ARG_TYPES); final Object dict = factoryMethod.invoke(null /* obj */, - new Object[] { context, locale, dictFile, dictNamePrefix }); + new Object[] { context, locale, dictFile, dictNamePrefix, account }); return (ExpandableBinaryDictionary) dict; } catch (final NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { @@ -332,17 +377,19 @@ public class DictionaryFacilitator { public void resetDictionaries(final Context context, final Locale[] newLocales, final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, + @Nullable final String account, final DictionaryInitializationListener listener) { resetDictionariesWithDictNamePrefix(context, newLocales, useContactsDict, - usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */); + usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */, + account); } @Nullable static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups, final Locale locale) { - for (int i = 0; i < dictionaryGroups.length; ++i) { - if (locale.equals(dictionaryGroups[i].mLocale)) { - return dictionaryGroups[i]; + for (DictionaryGroup dictionaryGroup : dictionaryGroups) { + if (locale.equals(dictionaryGroup.mLocale)) { + return dictionaryGroup; } } return null; @@ -350,11 +397,13 @@ public class DictionaryFacilitator { public void resetDictionariesWithDictNamePrefix(final Context context, final Locale[] newLocales, - final boolean useContactsDict, final boolean usePersonalizedDicts, + final boolean useContactsDict, + final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, @Nullable final DictionaryInitializationListener listener, - final String dictNamePrefix) { - final HashMap<Locale, ArrayList<String>> existingDictsToCleanup = new HashMap<>(); + final String dictNamePrefix, + @Nullable final String account) { + final HashMap<Locale, ArrayList<String>> existingDictionariesToCleanup = new HashMap<>(); // TODO: Make subDictTypesToUse configurable by resource or a static final list. final HashSet<String> subDictTypesToUse = new HashSet<>(); subDictTypesToUse.add(Dictionary.TYPE_USER); @@ -369,20 +418,20 @@ public class DictionaryFacilitator { // Gather all dictionaries. We'll remove them from the list to clean up later. for (final Locale newLocale : newLocales) { - final ArrayList<String> dictsForLocale = new ArrayList<>(); - existingDictsToCleanup.put(newLocale, dictsForLocale); + final ArrayList<String> dictTypeForLocale = new ArrayList<>(); + existingDictionariesToCleanup.put(newLocale, dictTypeForLocale); final DictionaryGroup currentDictionaryGroupForLocale = findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); if (null == currentDictionaryGroupForLocale) { continue; } for (final String dictType : SUB_DICT_TYPES) { - if (currentDictionaryGroupForLocale.hasDict(dictType)) { - dictsForLocale.add(dictType); + if (currentDictionaryGroupForLocale.hasDict(dictType, account)) { + dictTypeForLocale.add(dictType); } } - if (currentDictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN)) { - dictsForLocale.add(Dictionary.TYPE_MAIN); + if (currentDictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { + dictTypeForLocale.add(Dictionary.TYPE_MAIN); } } @@ -391,34 +440,35 @@ public class DictionaryFacilitator { final Locale newLocale = newLocales[i]; final DictionaryGroup dictionaryGroupForLocale = findDictionaryGroupWithLocale(mDictionaryGroups, newLocale); - final ArrayList<String> dictsToCleanupForLocale = existingDictsToCleanup.get(newLocale); + final ArrayList<String> dictTypesToCleanupForLocale = + existingDictionariesToCleanup.get(newLocale); final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale); final Dictionary mainDict; if (forceReloadMainDictionary || noExistingDictsForThisLocale - || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN)) { + || !dictionaryGroupForLocale.hasDict(Dictionary.TYPE_MAIN, account)) { mainDict = null; } else { mainDict = dictionaryGroupForLocale.getDict(Dictionary.TYPE_MAIN); - dictsToCleanupForLocale.remove(Dictionary.TYPE_MAIN); + dictTypesToCleanupForLocale.remove(Dictionary.TYPE_MAIN); } final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>(); for (final String subDictType : subDictTypesToUse) { final ExpandableBinaryDictionary subDict; if (noExistingDictsForThisLocale - || !dictionaryGroupForLocale.hasDict(subDictType)) { + || !dictionaryGroupForLocale.hasDict(subDictType, account)) { // Create a new dictionary. subDict = getSubDict(subDictType, context, newLocale, null /* dictFile */, - dictNamePrefix); + dictNamePrefix, account); } else { // Reuse the existing dictionary, and don't close it at the end subDict = dictionaryGroupForLocale.getSubDict(subDictType); - dictsToCleanupForLocale.remove(subDictType); + dictTypesToCleanupForLocale.remove(subDictType); } subDicts.put(subDictType, subDict); } - newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, subDicts); + newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, account, subDicts); } // Replace Dictionaries. @@ -437,9 +487,9 @@ public class DictionaryFacilitator { } // Clean up old dictionaries. - for (final Locale localeToCleanUp : existingDictsToCleanup.keySet()) { + for (final Locale localeToCleanUp : existingDictionariesToCleanup.keySet()) { final ArrayList<String> dictTypesToCleanUp = - existingDictsToCleanup.get(localeToCleanUp); + existingDictionariesToCleanup.get(localeToCleanUp); final DictionaryGroup dictionarySetToCleanup = findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp); for (final String dictType : dictTypesToCleanUp) { @@ -493,7 +543,8 @@ public class DictionaryFacilitator { @UsedForTesting public void resetDictionariesForTesting(final Context context, final Locale[] locales, final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, - final Map<String, Map<String, String>> additionalDictAttributes) { + final Map<String, Map<String, String>> additionalDictAttributes, + @Nullable final String account) { Dictionary mainDictionary = null; final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>(); @@ -507,7 +558,7 @@ public class DictionaryFacilitator { } else { final File dictFile = dictionaryFiles.get(dictType); final ExpandableBinaryDictionary dict = getSubDict( - dictType, context, locale, dictFile, "" /* dictNamePrefix */); + dictType, context, locale, dictFile, "" /* dictNamePrefix */, account); if (additionalDictAttributes.containsKey(dictType)) { dict.clearAndFlushDictionaryWithAdditionalAttributes( additionalDictAttributes.get(dictType)); @@ -520,7 +571,7 @@ public class DictionaryFacilitator { subDicts.put(dictType, dict); } } - dictionaryGroups[i] = new DictionaryGroup(locale, mainDictionary, subDicts); + dictionaryGroups[i] = new DictionaryGroup(locale, mainDictionary, account, subDicts); } mDictionaryGroups = dictionaryGroups; mMostProbableDictionaryGroup = dictionaryGroups[0]; @@ -576,7 +627,7 @@ public class DictionaryFacilitator { public boolean hasPersonalizationDictionary() { final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION)) { + if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION, null /* account */)) { return true; } } @@ -677,7 +728,8 @@ public class DictionaryFacilitator { // History dictionary in order to avoid suggesting them until the dictionary // consolidation is done. // TODO: Remove this hack when ready. - final int lowerCaseFreqInMainDict = dictionaryGroup.hasDict(Dictionary.TYPE_MAIN) ? + final int lowerCaseFreqInMainDict = dictionaryGroup.hasDict(Dictionary.TYPE_MAIN, + null /* account */) ? dictionaryGroup.getDict(Dictionary.TYPE_MAIN).getFrequency(lowerCasedWord) : Dictionary.NOT_A_PROBABILITY; if (maxFreq < lowerCaseFreqInMainDict diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java index b578159eb..3119ff82f 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java @@ -102,10 +102,12 @@ public class DictionaryFacilitatorLruCache { private void resetDictionariesForLocaleLocked(final DictionaryFacilitator dictionaryFacilitator, final Locale locale) { + // Note: Given that personalized dictionaries are not used here; we can pass null account. dictionaryFacilitator.resetDictionariesWithDictNamePrefix(mContext, new Locale[] { locale }, mUseContactsDictionary, false /* usePersonalizedDicts */, false /* forceReloadMainDictionary */, null /* listener */, - mDictionaryNamePrefix); + mDictionaryNamePrefix, + null /* account */); } public void setUseContactsDictionary(final boolean useContectsDictionary) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d6ec57fe6..45156a31e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -166,7 +166,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private RichInputMethodManager mRichImm; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; - final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); private final EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector = new EmojiAltPhysicalKeyDetector(); @@ -563,7 +562,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public LatinIME() { super(); mSettings = Settings.getInstance(); - mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); mStatsUtilsManager = StatsUtilsManager.getInstance(); mIsHardwareAcceleratedDrawingEnabled = @@ -577,7 +575,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen DebugFlags.init(PreferenceManager.getDefaultSharedPreferences(this)); RichInputMethodManager.init(this); mRichImm = RichInputMethodManager.getInstance(); - SubtypeSwitcher.init(this); KeyboardSwitcher.init(this); AudioAndHapticFeedbackManager.init(this); AccessibilityUtils.init(this); @@ -633,12 +630,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // been displayed. Opening dictionaries never affects responsivity as dictionaries are // asynchronously loaded. if (!mHandler.hasPendingReopenDictionaries()) { - resetDictionaryFacilitatorForLocale(locales); + resetDictionaryFacilitator(locales); } mDictionaryFacilitator.updateEnabledSubtypes(mRichImm.getMyEnabledInputMethodSubtypeList( true /* allowsImplicitlySelectedSubtypes */)); refreshPersonalizationDictionarySession(currentSettingsValues); mStatsUtilsManager.onLoadSettings(currentSettingsValues); + resetDictionaryFacilitatorIfNecessary(); } private void refreshPersonalizationDictionarySession( @@ -676,7 +674,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen void resetDictionaryFacilitatorIfNecessary() { final Locale[] subtypeSwitcherLocales = mRichImm.getCurrentSubtypeLocales(); - if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales)) { + if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales) + && mDictionaryFacilitator.isForAccount(mSettings.getCurrent().mAccount)) { return; } final Locale[] subtypeLocales; @@ -690,20 +689,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { subtypeLocales = subtypeSwitcherLocales; } - resetDictionaryFacilitatorForLocale(subtypeLocales); + resetDictionaryFacilitator(subtypeLocales); } /** - * Reset the facilitator by loading dictionaries for the locales and the current settings values + * Reset the facilitator by loading dictionaries for the locales and + * the current settings values. * * @param locales the locales */ - // TODO: make sure the current settings always have the right locales, and read from them - private void resetDictionaryFacilitatorForLocale(final Locale[] locales) { + // TODO: make sure the current settings always have the right locales, and read from them. + private void resetDictionaryFacilitator(final Locale[] locales) { final SettingsValues settingsValues = mSettings.getCurrent(); mDictionaryFacilitator.resetDictionaries(this /* context */, locales, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, - false /* forceReloadMainDictionary */, this); + false /* forceReloadMainDictionary */, + settingsValues.mAccount, + this /* DictionaryInitializationListener */); if (settingsValues.mAutoCorrectionEnabledPerUserSettings) { mInputLogic.mSuggest.setAutoCorrectionThreshold( settingsValues.mAutoCorrectionThreshold); @@ -718,7 +720,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final SettingsValues settingsValues = mSettings.getCurrent(); mDictionaryFacilitator.resetDictionaries(this /* context */, mDictionaryFacilitator.getLocales(), settingsValues.mUseContactsDict, - settingsValues.mUsePersonalizedDicts, true /* forceReloadMainDictionary */, this); + settingsValues.mUsePersonalizedDicts, + true /* forceReloadMainDictionary */, + settingsValues.mAccount, + this /* DictionaryInitializationListener */); } @Override @@ -869,7 +874,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() // is not guaranteed. It may even be called at the same time on a different thread. mRichImm.onSubtypeChanged(subtype); - mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentSubtype()); mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype), mSettings.getCurrent()); loadKeyboard(); @@ -886,7 +890,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // also wouldn't be consuming gesture data. mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER; mRichImm.refreshSubtypeCaches(); - mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentSubtype()); final KeyboardSwitcher switcher = mKeyboardSwitcher; switcher.updateKeyboardTheme(); final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView(); @@ -948,10 +951,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen Settings.getInstance().getCurrent().mDisplayOrientation, !isDifferentTextField); - if (isDifferentTextField) { - mSubtypeSwitcher.updateParametersOnStartInputView(); - } - // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); @@ -1934,7 +1933,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final SettingsValues settingsValues = mSettings.getCurrent(); mDictionaryFacilitator.resetDictionaries(this, new Locale[] { locale }, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, - false /* forceReloadMainDictionary */, this /* listener */); + false /* forceReloadMainDictionary */, + settingsValues.mAccount, + this /* DictionaryInitializationListener */); } // DO NOT USE THIS for any other purpose than testing. diff --git a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java index 2dbab0a3f..8926c06b1 100644 --- a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java @@ -114,7 +114,7 @@ public class PersonalizationHelperForDictionaryFacilitator { return personalizationDict; } personalizationDict = PersonalizationDictionary.getDictionary(context, locale, - null /* dictFile */, "" /* dictNamePrefix */); + null /* dictFile */, "" /* dictNamePrefix */, null /* account */); mPersonalizationDictsToUpdate.put(locale, personalizationDict); return personalizationDict; } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index d8b018989..811af4bd7 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -36,6 +36,7 @@ import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.latin.settings.AdditionalFeaturesSettingUtils; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; +import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils; import com.android.inputmethod.latin.utils.NetworkConnectivityUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -523,6 +524,15 @@ public class RichInputMethodManager { + (mShortcutSubtype == null ? "<null>" : ( mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); } + final RichInputMethodSubtype richSubtype = mCurrentRichInputMethodSubtype; + final boolean implicitlyEnabledSubtype = checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled( + richSubtype.getRawSubtype()); + final Locale systemLocale = mContext.getResources().getConfiguration().locale; + LanguageOnSpacebarUtils.onSubtypeChanged( + richSubtype, implicitlyEnabledSubtype, systemLocale); + LanguageOnSpacebarUtils.setEnabledSubtypes(getMyEnabledInputMethodSubtypeList( + true /* allowsImplicitlySelectedSubtypes */)); + // TODO: Update an icon for shortcut IME final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts = getInputMethodManager().getShortcutInputMethodsAndSubtypes(); diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java deleted file mode 100644 index d7a03d40b..000000000 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 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 android.content.Context; -import android.content.res.Resources; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils; -import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; - -import java.util.List; - -import javax.annotation.Nonnull; - -public final class SubtypeSwitcher { - private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); - - private /* final */ RichInputMethodManager mRichImm; - private /* final */ Resources mResources; - - public static SubtypeSwitcher getInstance() { - return sInstance; - } - - public static void init(final Context context) { - SubtypeLocaleUtils.init(context); - RichInputMethodManager.init(context); - sInstance.initialize(context); - } - - private SubtypeSwitcher() { - // Intentional empty constructor for singleton. - } - - private void initialize(final Context context) { - if (mResources != null) { - return; - } - mResources = context.getResources(); - mRichImm = RichInputMethodManager.getInstance(); - - onSubtypeChanged(mRichImm.getCurrentSubtype()); - updateParametersOnStartInputView(); - } - - /** - * Update parameters which are changed outside LatinIME. This parameters affect UI so that they - * should be updated every time onStartInputView is called. - */ - public void updateParametersOnStartInputView() { - final List<InputMethodSubtype> enabledSubtypesOfThisIme = - mRichImm.getMyEnabledInputMethodSubtypeList(true); - LanguageOnSpacebarUtils.setEnabledSubtypes(enabledSubtypesOfThisIme); - } - - // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. - public void onSubtypeChanged(@Nonnull final RichInputMethodSubtype richSubtype) { - final boolean implicitlyEnabledSubtype = mRichImm - .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(richSubtype.getRawSubtype()); - LanguageOnSpacebarUtils.onSubtypeChanged( - richSubtype, implicitlyEnabledSubtype, mResources.getConfiguration().locale); - } -} diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index 2b7fb1748..2d2b3d0a6 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -36,6 +36,8 @@ import java.io.File; import java.util.Arrays; import java.util.Locale; +import javax.annotation.Nullable; + /** * An expandable dictionary that stores the words in the user dictionary provider into a binary * dictionary file to use it from native code. @@ -104,7 +106,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. @ExternallyReferenced public static UserBinaryDictionary getDictionary(final Context context, final Locale locale, - final File dictFile, final String dictNamePrefix) { + final File dictFile, final String dictNamePrefix, @Nullable final String account) { return new UserBinaryDictionary(context, locale, false /* alsoUseMoreRestrictiveLocales */, dictFile, dictNamePrefix + NAME); } diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java index 39d9596ef..f663fe96a 100644 --- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java @@ -25,6 +25,8 @@ 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(); @@ -40,7 +42,7 @@ public class ContextualDictionary extends ExpandableBinaryDictionary { @SuppressWarnings("unused") @ExternallyReferenced public static ContextualDictionary getDictionary(final Context context, final Locale locale, - final File dictFile, final String dictNamePrefix) { + final File dictFile, final String dictNamePrefix, @Nullable final String account) { return new ContextualDictionary(context, locale, dictFile); } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java index 33d1273f7..76451cc6b 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java @@ -24,6 +24,8 @@ 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(); @@ -37,7 +39,8 @@ public class PersonalizationDictionary extends DecayingExpandableBinaryDictionar @SuppressWarnings("unused") @ExternallyReferenced public static PersonalizationDictionary getDictionary(final Context context, - final Locale locale, final File dictFile, final String dictNamePrefix) { + final Locale locale, final File dictFile, final String dictNamePrefix, + @Nullable final String account) { return PersonalizationHelper.getPersonalizationDictionary(context, locale); } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index b595f3974..4231450c1 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -64,7 +64,8 @@ public class PersonalizationHelper { return dict; } } - final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale); + final UserHistoryDictionary dict = new UserHistoryDictionary( + context, locale, accountName); sLangUserHistoryDictCache.put(lookupStr, new SoftReference<>(dict)); return dict; } diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java index 946835cbc..2e41027a4 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -37,20 +37,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * Locally gathers stats about the words user types and various other signals like auto-correction - * cancellation or manual picks. This allows the keyboard to adapt to the typist over time. + * Locally gathers statistics about the words user types and various other signals like + * auto-correction cancellation or manual picks. This allows the keyboard to adapt to the + * typist over time. */ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase { static final String NAME = UserHistoryDictionary.class.getSimpleName(); // TODO: Make this constructor private - UserHistoryDictionary(final Context context, final Locale locale) { + UserHistoryDictionary(final Context context, final Locale locale, + @Nullable final String account) { super(context, - getUserHistoryDictName( - NAME, - locale, - null /* dictFile */, - context), + getUserHistoryDictName(NAME, locale, null /* dictFile */, account), locale, Dictionary.TYPE_USER_HISTORY, null /* dictFile */); @@ -61,24 +59,21 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas */ @UsedForTesting static String getUserHistoryDictName(final String name, final Locale locale, - @Nullable final File dictFile, final Context context) { + @Nullable final File dictFile, @Nullable final String account) { if (!ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) { return getDictName(name, locale, dictFile); } - return getUserHistoryDictNamePerAccount(name, locale, dictFile, context); + return getUserHistoryDictNamePerAccount(name, locale, dictFile, account); } /** * Uses the currently signed in account to determine the dictionary name. */ private static String getUserHistoryDictNamePerAccount(final String name, final Locale locale, - @Nullable final File dictFile, final Context context) { + @Nullable final File dictFile, @Nullable final String account) { if (dictFile != null) { return dictFile.getName(); } - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - final String account = prefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, - null /* default */); String dictName = name + "." + locale.toString(); if (account != null) { dictName += "." + account; @@ -90,14 +85,7 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas @SuppressWarnings("unused") @ExternallyReferenced public static UserHistoryDictionary getDictionary(final Context context, final Locale locale, - final File dictFile, final String dictNamePrefix) { - final String account; - if (ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) { - account = PreferenceManager.getDefaultSharedPreferences(context) - .getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null /* default */); - } else { - account = null; - } + final File dictFile, final String dictNamePrefix, @Nullable final String account) { return PersonalizationHelper.getUserHistoryDictionary(context, locale, account); } diff --git a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java index 4bd15d037..8f4ec4f1b 100644 --- a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java @@ -33,9 +33,8 @@ import android.widget.Toast; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.accounts.LoginAccountUtils; import com.android.inputmethod.latin.accounts.AccountStateChangedListener; +import com.android.inputmethod.latin.accounts.LoginAccountUtils; import com.android.inputmethod.latin.define.ProductionFlags; import javax.annotation.Nullable; @@ -50,12 +49,15 @@ import javax.annotation.Nullable; */ public final class AccountsSettingsFragment extends SubScreenFragment { private static final String PREF_SYNC_NOW = "pref_beanstalk"; + private static final String PREF_CLEAR_SYNC_DATA = "pref_beanstalk_clear_data"; static final String PREF_ACCCOUNT_SWITCHER = "account_switcher"; private final DialogInterface.OnClickListener mAccountChangedListener = new AccountChangedListener(); private final Preference.OnPreferenceClickListener mSyncNowListener = new SyncNowListener(); + private final Preference.OnPreferenceClickListener mClearSyncDataListener = + new ClearSyncDataListener(); @Override public void onCreate(final Bundle icicle) { @@ -63,12 +65,6 @@ public final class AccountsSettingsFragment extends SubScreenFragment { addPreferencesFromResource(R.xml.prefs_screen_accounts); final Resources res = getResources(); - final Context context = getActivity(); - - // When we are called from the Settings application but we are not already running, some - // singleton and utility classes may not have been initialized. We have to call - // initialization method of these classes here. See {@link LatinIME#onCreate()}. - SubtypeSwitcher.init(context); if (ProductionFlags.IS_METRICS_LOGGING_SUPPORTED) { final Preference enableMetricsLogging = @@ -86,13 +82,18 @@ public final class AccountsSettingsFragment extends SubScreenFragment { removePreference(PREF_ACCCOUNT_SWITCHER); removePreference(PREF_ENABLE_CLOUD_SYNC); removePreference(PREF_SYNC_NOW); + removePreference(PREF_CLEAR_SYNC_DATA); } if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) { removePreference(PREF_ENABLE_CLOUD_SYNC); removePreference(PREF_SYNC_NOW); + removePreference(PREF_CLEAR_SYNC_DATA); } else { final Preference syncNowPreference = findPreference(PREF_SYNC_NOW); syncNowPreference.setOnPreferenceClickListener(mSyncNowListener); + + final Preference clearSyncDataPreference = findPreference(PREF_CLEAR_SYNC_DATA); + clearSyncDataPreference.setOnPreferenceClickListener(mClearSyncDataListener); } } @@ -136,7 +137,7 @@ public final class AccountsSettingsFragment extends SubScreenFragment { final String[] accountsForLogin = LoginAccountUtils.getAccountsForLogin(context); accountSwitcher.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override - public boolean onPreferenceClick(Preference preference) { + public boolean onPreferenceClick(final Preference preference) { if (accountsForLogin.length == 0) { // TODO: Handle account addition. Toast.makeText(getActivity(), getString(R.string.account_select_cancel), @@ -229,7 +230,7 @@ public final class AccountsSettingsFragment extends SubScreenFragment { */ class AccountChangedListener implements DialogInterface.OnClickListener { @Override - public void onClick(DialogInterface dialog, int which) { + public void onClick(final DialogInterface dialog, final int which) { final String oldAccount = getSignedInAccountName(); switch (which) { case DialogInterface.BUTTON_POSITIVE: // Signed in @@ -263,4 +264,30 @@ public final class AccountsSettingsFragment extends SubScreenFragment { return true; } } + + /** + * Listener that initiates the process of deleting user's data from the cloud. + */ + class ClearSyncDataListener implements Preference.OnPreferenceClickListener { + @Override + public boolean onPreferenceClick(final Preference preference) { + final AlertDialog confirmationDialog = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.clear_sync_data_title) + .setMessage(R.string.clear_sync_data_confirmation) + .setPositiveButton(R.string.clear_sync_data_ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + AccountStateChangedListener.forceDelete( + getSignedInAccountName()); + } + } + }) + .setNegativeButton(R.string.clear_sync_data_cancel, null /* OnClickListener */) + .create(); + confirmationDialog.show(); + return true; + } + } } diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 5f1a7af44..0669026d8 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -36,6 +36,7 @@ import java.util.Arrays; import java.util.Locale; import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * When you call the constructor of this class, you may want to change the current system locale by @@ -120,6 +121,8 @@ public class SettingsValues { public final float mKeyPreviewDismissEndXScale; public final float mKeyPreviewDismissEndYScale; + @Nullable public final String mAccount; + public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res, @Nonnull final InputAttributes inputAttributes) { mLocale = res.getConfiguration().locale; @@ -176,6 +179,8 @@ public class SettingsValues { mPlausibilityThreshold = Settings.readPlausibilityThreshold(res); mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res); mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); + mAccount = prefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, + null /* default */); mGestureFloatingPreviewTextEnabled = !mInputAttributes.mDisableGestureFloatingPreviewText && prefs.getBoolean(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); mPhraseGestureEnabled = Settings.readPhraseGestureEnabled(prefs, res); |