aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java1
-rw-r--r--java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java (renamed from java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java)66
-rw-r--r--java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityNodeProvider.java (renamed from java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java)17
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java7
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java19
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java17
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java259
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java29
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java5
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java69
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java23
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java16
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java13
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java11
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java7
15 files changed, 256 insertions, 303 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index bc094b117..d50dd3ee6 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -68,7 +68,6 @@ public final class AccessibilityUtils {
// These only need to be initialized if the kill switch is off.
sInstance.initInternal(context);
KeyCodeDescriptionMapper.init();
- AccessibleKeyboardViewProxy.init(context);
}
public static AccessibilityUtils getInstance() {
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
index 15f79f3de..10929424b 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
@@ -36,9 +36,7 @@ import com.android.inputmethod.keyboard.MainKeyboardView;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
-public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
- private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy();
-
+public final class MainKeyboardAccessibilityDelegate extends AccessibilityDelegateCompat {
/** Map of keyboard modes to resource IDs. */
private static final SparseIntArray KEYBOARD_MODE_RES_IDS = new SparseIntArray();
@@ -54,9 +52,9 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_URL, R.string.keyboard_mode_url);
}
- private MainKeyboardView mView;
+ private final MainKeyboardView mView;
private Keyboard mKeyboard;
- private AccessibilityEntityProvider mAccessibilityNodeProvider;
+ private MainKeyboardAccessibilityNodeProvider mAccessibilityNodeProvider;
private Key mLastHoverKey = null;
@@ -69,46 +67,14 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
private int mLastKeyboardMode = KEYBOARD_IS_HIDDEN;
private static final int KEYBOARD_IS_HIDDEN = -1;
- public static void init(final Context context) {
- sInstance.initInternal(context);
- }
-
- public static AccessibleKeyboardViewProxy getInstance() {
- return sInstance;
- }
-
- private AccessibleKeyboardViewProxy() {
- // Not publicly instantiable.
- }
-
- private void initInternal(final Context context) {
+ public MainKeyboardAccessibilityDelegate(final MainKeyboardView view) {
+ final Context context = view.getContext();
mEdgeSlop = context.getResources().getDimensionPixelSize(
R.dimen.config_accessibility_edge_slop);
- }
-
- /**
- * Sets the view wrapped by this proxy.
- *
- * @param view The view to wrap.
- */
- public void setView(final MainKeyboardView view) {
- if (view == null) {
- // Ignore null views.
- return;
- }
mView = view;
// Ensure that the view has an accessibility delegate.
ViewCompat.setAccessibilityDelegate(view, this);
-
- if (mAccessibilityNodeProvider == null) {
- return;
- }
- mAccessibilityNodeProvider.setView(view);
-
- // Since this class is constructed lazily, we might not get a subsequent
- // call to setKeyboard() and therefore need to call it now.
- setKeyboard(view.getKeyboard());
}
/**
@@ -156,9 +122,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
* Called when the keyboard is hidden and accessibility is enabled.
*/
public void onHideWindow() {
- if (mView == null) {
- return;
- }
announceKeyboardHidden();
mLastKeyboardMode = KEYBOARD_IS_HIDDEN;
}
@@ -264,7 +227,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
}
/**
- * Proxy method for View.getAccessibilityNodeProvider(). This method is called in SDK
+ * Delegate method for View.getAccessibilityNodeProvider(). This method is called in SDK
* version 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) and higher to obtain the virtual
* node hierarchy provider.
*
@@ -272,10 +235,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
* @return The accessibility node provider for the current keyboard.
*/
@Override
- public AccessibilityEntityProvider getAccessibilityNodeProvider(final View host) {
- if (mView == null) {
- return null;
- }
+ public MainKeyboardAccessibilityNodeProvider getAccessibilityNodeProvider(final View host) {
return getAccessibilityNodeProvider();
}
@@ -288,10 +248,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
* @return {@code true} if the event is handled
*/
public boolean dispatchHoverEvent(final MotionEvent event, final KeyDetector keyDetector) {
- if (mView == null) {
- return false;
- }
-
final int x = (int) event.getX();
final int y = (int) event.getY();
final Key previousKey = mLastHoverKey;
@@ -325,14 +281,14 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
}
/**
- * @return A lazily-instantiated node provider for this view proxy.
+ * @return A lazily-instantiated node provider for this view delegate.
*/
- private AccessibilityEntityProvider getAccessibilityNodeProvider() {
+ private MainKeyboardAccessibilityNodeProvider getAccessibilityNodeProvider() {
// Instantiate the provide only when requested. Since the system
// will call this method multiple times it is a good practice to
// cache the provider instance.
if (mAccessibilityNodeProvider == null) {
- mAccessibilityNodeProvider = new AccessibilityEntityProvider(mView);
+ mAccessibilityNodeProvider = new MainKeyboardAccessibilityNodeProvider(mView);
}
return mAccessibilityNodeProvider;
}
@@ -417,7 +373,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
if (key == null) {
return false;
}
- final AccessibilityEntityProvider provider = getAccessibilityNodeProvider();
+ final MainKeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider();
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityNodeProvider.java
index ec1ab3565..f69d316c9 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityNodeProvider.java
@@ -47,8 +47,8 @@ import java.util.List;
* virtual views, thus conveying their logical structure.
* </p>
*/
-public final class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat {
- private static final String TAG = AccessibilityEntityProvider.class.getSimpleName();
+public final class MainKeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderCompat {
+ private static final String TAG = MainKeyboardAccessibilityNodeProvider.class.getSimpleName();
private static final int UNDEFINED = Integer.MIN_VALUE;
private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper;
@@ -64,23 +64,14 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
private int mAccessibilityFocusedView = UNDEFINED;
/** The current keyboard view. */
- private KeyboardView mKeyboardView;
+ private final KeyboardView mKeyboardView;
/** The current keyboard. */
private Keyboard mKeyboard;
- public AccessibilityEntityProvider(final KeyboardView keyboardView) {
+ public MainKeyboardAccessibilityNodeProvider(final KeyboardView keyboardView) {
mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance();
mAccessibilityUtils = AccessibilityUtils.getInstance();
- setView(keyboardView);
- }
-
- /**
- * Sets the keyboard view represented by this node provider.
- *
- * @param keyboardView The keyboard view to represent.
- */
- public void setView(final KeyboardView keyboardView) {
mKeyboardView = keyboardView;
updateParentLocation();
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 0e667bc1c..589e99ea6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -26,7 +26,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
-import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
import com.android.inputmethod.keyboard.internal.KeyboardState;
@@ -148,6 +147,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
public void onHideWindow() {
mIsAutoCorrectionActive = false;
+ mKeyboardView.onHideWindow();
}
private void setKeyboard(final Keyboard keyboard) {
@@ -353,11 +353,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled(
isHardwareAcceleratedDrawingEnabled);
mEmojiPalettesView.setKeyboardActionListener(mLatinIME);
-
- // This always needs to be set since the accessibility state can
- // potentially change without the input view being re-created.
- AccessibleKeyboardViewProxy.getInstance().setView(mKeyboardView);
-
return mCurrentInputView;
}
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index ecef8cc6c..8f79a9128 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -39,7 +39,7 @@ import android.view.inputmethod.InputMethodSubtype;
import android.widget.TextView;
import com.android.inputmethod.accessibility.AccessibilityUtils;
-import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
+import com.android.inputmethod.accessibility.MainKeyboardAccessibilityDelegate;
import com.android.inputmethod.annotations.ExternallyReferenced;
import com.android.inputmethod.keyboard.internal.DrawingHandler;
import com.android.inputmethod.keyboard.internal.DrawingPreviewPlacerView;
@@ -179,6 +179,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private final DrawingHandler mDrawingHandler =
new DrawingHandler(this);
+ private final MainKeyboardAccessibilityDelegate mAccessibilityDelegate;
+
public MainKeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.mainKeyboardViewStyle);
}
@@ -278,6 +280,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mLanguageOnSpacebarHorizontalMargin = (int)getResources().getDimension(
R.dimen.config_language_on_spacebar_horizontal_margin);
+
+ mAccessibilityDelegate = new MainKeyboardAccessibilityDelegate(this);
}
@Override
@@ -404,9 +408,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
ResearchLogger.mainKeyboardView_setKeyboard(keyboard, orientation);
}
- // This always needs to be set since the accessibility state can
- // potentially change without the keyboard being set again.
- AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard);
+ mAccessibilityDelegate.setKeyboard(keyboard);
}
/**
@@ -769,6 +771,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mMoreKeysKeyboardCache.clear();
}
+ public void onHideWindow() {
+ if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
+ mAccessibilityDelegate.onHideWindow();
+ }
+ }
+
/**
* Receives hover events from the input framework.
*
@@ -779,8 +787,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
@Override
public boolean dispatchHoverEvent(final MotionEvent event) {
if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
- return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(
- event, mKeyDetector);
+ return mAccessibilityDelegate.dispatchHoverEvent(event, mKeyDetector);
}
// Reflection doesn't support calling superclass methods.
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 09d0ea210..9bc01a2b1 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -29,6 +29,7 @@ import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.personalization.AccountUtils;
import com.android.inputmethod.latin.utils.StringUtils;
@@ -61,9 +62,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
/** The number of contacts in the most recent dictionary rebuild. */
static private int sContactCountAtLastRebuild = 0;
- /** The locale for this contacts dictionary. Controls name bigram predictions. */
- public final Locale mLocale;
-
private ContentObserver mObserver;
/**
@@ -71,11 +69,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
*/
private final boolean mUseFirstLastBigrams;
- public ContactsBinaryDictionary(final Context context, final Locale locale) {
- this(context, locale, null /* dictFile */);
- }
-
- public ContactsBinaryDictionary(final Context context, final Locale locale,
+ private ContactsBinaryDictionary(final Context context, final Locale locale,
final File dictFile) {
this(context, locale, dictFile, NAME);
}
@@ -84,12 +78,17 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
final File dictFile, final String name) {
super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_CONTACTS,
dictFile);
- mLocale = locale;
mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale);
registerObserver(context);
reloadDictionaryIfRequired();
}
+ @UsedForTesting
+ public static ContactsBinaryDictionary getDictionary(final Context context, final Locale locale,
+ final File dictFile) {
+ return new ContactsBinaryDictionary(context, locale, dictFile);
+ }
+
private synchronized void registerObserver(final Context context) {
if (mObserver != null) return;
ContentResolver cres = context.getContentResolver();
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index b6fcbd1d6..627793f18 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -24,7 +24,6 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
-import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ExecutorUtils;
@@ -32,10 +31,14 @@ import com.android.inputmethod.latin.utils.LanguageModelParam;
import com.android.inputmethod.latin.utils.SuggestionResults;
import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -54,7 +57,7 @@ public class DictionaryFacilitatorForSuggest {
// To synchronize assigning mDictionaries to ensure closing dictionaries.
private Object mLock = new Object();
- private static final String[] dictTypesOrderedToGetSuggestion =
+ private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION =
new String[] {
Dictionary.TYPE_MAIN,
Dictionary.TYPE_USER_HISTORY,
@@ -63,13 +66,30 @@ public class DictionaryFacilitatorForSuggest {
Dictionary.TYPE_CONTACTS
};
+ private static final Map<String, Class<? extends ExpandableBinaryDictionary>>
+ DICT_TYPE_TO_CLASS = CollectionUtils.newHashMap();
+
+ 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);
+ }
+
+ 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 };
+
+ private static final String[] SUB_DICT_TYPES =
+ Arrays.copyOfRange(DICT_TYPES_ORDERED_TO_GET_SUGGESTION, 1 /* start */,
+ DICT_TYPES_ORDERED_TO_GET_SUGGESTION.length);
+
/**
* Class contains dictionaries for a locale.
*/
private static class Dictionaries {
public final Locale mLocale;
- public final ConcurrentHashMap<String, Dictionary> mDictMap =
- CollectionUtils.newConcurrentHashMap();
+ private Dictionary mMainDict;
public final ConcurrentHashMap<String, ExpandableBinaryDictionary> mSubDictMap =
CollectionUtils.newConcurrentHashMap();
@@ -78,41 +98,36 @@ public class DictionaryFacilitatorForSuggest {
}
public Dictionaries(final Locale locale, final Dictionary mainDict,
- final ExpandableBinaryDictionary contactsDict,
- final ExpandableBinaryDictionary userDict,
- final ExpandableBinaryDictionary userHistoryDict,
- final ExpandableBinaryDictionary personalizationDict) {
+ final Map<String, ExpandableBinaryDictionary> subDicts) {
mLocale = locale;
// Main dictionary can be asynchronously loaded.
setMainDict(mainDict);
- setSubDict(Dictionary.TYPE_CONTACTS, contactsDict);
- setSubDict(Dictionary.TYPE_USER, userDict);
- setSubDict(Dictionary.TYPE_USER_HISTORY, userHistoryDict);
- setSubDict(Dictionary.TYPE_PERSONALIZATION, personalizationDict);
+ for (final Map.Entry<String, ExpandableBinaryDictionary> entry : subDicts.entrySet()) {
+ setSubDict(entry.getKey(), entry.getValue());
+ }
}
private void setSubDict(final String dictType, final ExpandableBinaryDictionary dict) {
if (dict != null) {
- mDictMap.put(dictType, dict);
mSubDictMap.put(dictType, dict);
}
}
public void setMainDict(final Dictionary mainDict) {
// Close old dictionary if exists. Main dictionary can be assigned multiple times.
- final Dictionary oldDict;
- if (mainDict != null) {
- oldDict = mDictMap.put(Dictionary.TYPE_MAIN, mainDict);
- } else {
- oldDict = mDictMap.remove(Dictionary.TYPE_MAIN);
- }
+ final Dictionary oldDict = mMainDict;
+ mMainDict = mainDict;
if (oldDict != null && mainDict != oldDict) {
oldDict.close();
}
}
- public Dictionary getMainDict() {
- return mDictMap.get(Dictionary.TYPE_MAIN);
+ public Dictionary getDict(final String dictType) {
+ if (Dictionary.TYPE_MAIN.equals(dictType)) {
+ return mMainDict;
+ } else {
+ return getSubDict(dictType);
+ }
}
public ExpandableBinaryDictionary getSubDict(final String dictType) {
@@ -120,12 +135,20 @@ public class DictionaryFacilitatorForSuggest {
}
public boolean hasDict(final String dictType) {
- return mDictMap.containsKey(dictType);
+ if (Dictionary.TYPE_MAIN.equals(dictType)) {
+ return mMainDict != null;
+ } else {
+ return mSubDictMap.containsKey(dictType);
+ }
}
public void closeDict(final String dictType) {
- final Dictionary dict = mDictMap.remove(dictType);
- mSubDictMap.remove(dictType);
+ final Dictionary dict;
+ if (Dictionary.TYPE_MAIN.equals(dictType)) {
+ dict = mMainDict;
+ } else {
+ dict = mSubDictMap.remove(dictType);
+ }
if (dict != null) {
dict.close();
}
@@ -142,6 +165,26 @@ public class DictionaryFacilitatorForSuggest {
return mDictionaries.mLocale;
}
+ private static ExpandableBinaryDictionary getSubDict(final String dictType,
+ final Context context, final Locale locale, final File dictFile) {
+ final Class<? extends ExpandableBinaryDictionary> dictClass =
+ DICT_TYPE_TO_CLASS.get(dictType);
+ if (dictClass == null) {
+ return null;
+ }
+ try {
+ 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 });
+ return (ExpandableBinaryDictionary) dict;
+ } catch (final NoSuchMethodException | SecurityException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ Log.e(TAG, "Cannot create dictionary: " + dictType, e);
+ return null;
+ }
+ }
+
public void resetDictionaries(final Context context, final Locale newLocale,
final boolean useContactsDict, final boolean usePersonalizedDicts,
final boolean forceReloadMainDictionary,
@@ -149,64 +192,44 @@ public class DictionaryFacilitatorForSuggest {
final boolean localeHasBeenChanged = !newLocale.equals(mDictionaries.mLocale);
// We always try to have the main dictionary. Other dictionaries can be unused.
final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary;
- final boolean closeContactsDictionary = localeHasBeenChanged || !useContactsDict;
- final boolean closeUserDictionary = localeHasBeenChanged;
- final boolean closeUserHistoryDictionary = localeHasBeenChanged || !usePersonalizedDicts;
- final boolean closePersonalizationDictionary =
- localeHasBeenChanged || !usePersonalizedDicts;
+ // TODO: Make subDictTypesToUse configurable by resource or a static final list.
+ final Set<String> subDictTypesToUse = CollectionUtils.newHashSet();
+ if (useContactsDict) {
+ subDictTypesToUse.add(Dictionary.TYPE_CONTACTS);
+ }
+ subDictTypesToUse.add(Dictionary.TYPE_USER);
+ if (usePersonalizedDicts) {
+ subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY);
+ subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION);
+ }
final Dictionary newMainDict;
if (reloadMainDictionary) {
// The main dictionary will be asynchronously loaded.
newMainDict = null;
} else {
- newMainDict = mDictionaries.getMainDict();
- }
-
- // Open or move contacts dictionary.
- final ExpandableBinaryDictionary newContactsDict;
- if (!closeContactsDictionary && mDictionaries.hasDict(Dictionary.TYPE_CONTACTS)) {
- newContactsDict = mDictionaries.getSubDict(Dictionary.TYPE_CONTACTS);
- } else if (useContactsDict) {
- newContactsDict = new ContactsBinaryDictionary(context, newLocale);
- } else {
- newContactsDict = null;
- }
-
- // Open or move user dictionary.
- final ExpandableBinaryDictionary newUserDictionary;
- if (!closeUserDictionary && mDictionaries.hasDict(Dictionary.TYPE_USER)) {
- newUserDictionary = mDictionaries.getSubDict(Dictionary.TYPE_USER);
- } else {
- newUserDictionary = new UserBinaryDictionary(context, newLocale);
- mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context);
+ newMainDict = mDictionaries.getDict(Dictionary.TYPE_MAIN);
}
- // Open or move user history dictionary.
- final ExpandableBinaryDictionary newUserHistoryDict;
- if (!closeUserHistoryDictionary && mDictionaries.hasDict(Dictionary.TYPE_USER_HISTORY)) {
- newUserHistoryDict = mDictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY);
- } else if (usePersonalizedDicts) {
- newUserHistoryDict = PersonalizationHelper.getUserHistoryDictionary(context, newLocale);
- } else {
- newUserHistoryDict = null;
- }
-
- // Open or move personalization dictionary.
- final ExpandableBinaryDictionary newPersonalizationDict;
- if (!closePersonalizationDictionary
- && mDictionaries.hasDict(Dictionary.TYPE_PERSONALIZATION)) {
- newPersonalizationDict = mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION);
- } else if (usePersonalizedDicts) {
- newPersonalizationDict =
- PersonalizationHelper.getPersonalizationDictionary(context, newLocale);
- } else {
- newPersonalizationDict = null;
+ final Map<String, ExpandableBinaryDictionary> subDicts = CollectionUtils.newHashMap();
+ for (final String dictType : SUB_DICT_TYPES) {
+ if (!subDictTypesToUse.contains(dictType)) {
+ // This dictionary will not be used.
+ continue;
+ }
+ final ExpandableBinaryDictionary dict;
+ if (!localeHasBeenChanged && mDictionaries.hasDict(dictType)) {
+ // Continue to use current dictionary.
+ dict = mDictionaries.getSubDict(dictType);
+ } else {
+ // Start to use new dictionary.
+ dict = getSubDict(dictType, context, newLocale, null /* dictFile */);
+ }
+ subDicts.put(dictType, dict);
}
// Replace Dictionaries.
- final Dictionaries newDictionaries = new Dictionaries(newLocale, newMainDict,
- newContactsDict, newUserDictionary, newUserHistoryDict, newPersonalizationDict);
+ final Dictionaries newDictionaries = new Dictionaries(newLocale, newMainDict, subDicts);
final Dictionaries oldDictionaries;
synchronized (mLock) {
oldDictionaries = mDictionaries;
@@ -218,24 +241,15 @@ public class DictionaryFacilitatorForSuggest {
if (listener != null) {
listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
}
-
// Clean up old dictionaries.
if (reloadMainDictionary) {
oldDictionaries.closeDict(Dictionary.TYPE_MAIN);
}
- if (closeContactsDictionary) {
- oldDictionaries.closeDict(Dictionary.TYPE_CONTACTS);
- }
- if (closeUserDictionary) {
- oldDictionaries.closeDict(Dictionary.TYPE_USER);
- }
- if (closeUserHistoryDictionary) {
- oldDictionaries.closeDict(Dictionary.TYPE_USER_HISTORY);
- }
- if (closePersonalizationDictionary) {
- oldDictionaries.closeDict(Dictionary.TYPE_PERSONALIZATION);
+ for (final String dictType : SUB_DICT_TYPES) {
+ if (localeHasBeenChanged || !subDictTypesToUse.contains(dictType)) {
+ oldDictionaries.closeDict(dictType);
+ }
}
- oldDictionaries.mDictMap.clear();
oldDictionaries.mSubDictMap.clear();
}
@@ -269,52 +283,28 @@ public class DictionaryFacilitatorForSuggest {
final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles,
final Map<String, Map<String, String>> additionalDictAttributes) {
Dictionary mainDictionary = null;
- ContactsBinaryDictionary contactsDictionary = null;
- UserBinaryDictionary userDictionary = null;
- UserHistoryDictionary userHistoryDictionary = null;
- PersonalizationDictionary personalizationDictionary = null;
+ final Map<String, ExpandableBinaryDictionary> subDicts = CollectionUtils.newHashMap();
for (final String dictType : dictionaryTypes) {
if (dictType.equals(Dictionary.TYPE_MAIN)) {
mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, locale);
- } else if (dictType.equals(Dictionary.TYPE_USER_HISTORY)) {
- userHistoryDictionary =
- PersonalizationHelper.getUserHistoryDictionary(context, locale);
- // Staring with an empty user history dictionary for testing.
- // Testing program may populate this dictionary before actual testing.
- userHistoryDictionary.reloadDictionaryIfRequired();
- userHistoryDictionary.waitAllTasksForTests();
+ } else {
+ final File dictFile = dictionaryFiles.get(dictType);
+ final ExpandableBinaryDictionary dict = getSubDict(
+ dictType, context, locale, dictFile);
if (additionalDictAttributes.containsKey(dictType)) {
- userHistoryDictionary.clearAndFlushDictionaryWithAdditionalAttributes(
+ dict.clearAndFlushDictionaryWithAdditionalAttributes(
additionalDictAttributes.get(dictType));
}
- } else if (dictType.equals(Dictionary.TYPE_PERSONALIZATION)) {
- personalizationDictionary =
- PersonalizationHelper.getPersonalizationDictionary(context, locale);
- // Staring with an empty personalization dictionary for testing.
- // Testing program may populate this dictionary before actual testing.
- personalizationDictionary.reloadDictionaryIfRequired();
- personalizationDictionary.waitAllTasksForTests();
- if (additionalDictAttributes.containsKey(dictType)) {
- personalizationDictionary.clearAndFlushDictionaryWithAdditionalAttributes(
- additionalDictAttributes.get(dictType));
+ if (dict == null) {
+ throw new RuntimeException("Unknown dictionary type: " + dictType);
}
- } else if (dictType.equals(Dictionary.TYPE_USER)) {
- final File file = dictionaryFiles.get(dictType);
- userDictionary = new UserBinaryDictionary(context, locale, file);
- userDictionary.reloadDictionaryIfRequired();
- userDictionary.waitAllTasksForTests();
- } else if (dictType.equals(Dictionary.TYPE_CONTACTS)) {
- final File file = dictionaryFiles.get(dictType);
- contactsDictionary = new ContactsBinaryDictionary(context, locale, file);
- contactsDictionary.reloadDictionaryIfRequired();
- contactsDictionary.waitAllTasksForTests();
- } else {
- throw new RuntimeException("Unknown dictionary type: " + dictType);
+ dict.reloadDictionaryIfRequired();
+ dict.waitAllTasksForTests();
+ subDicts.put(dictType, dict);
}
}
- mDictionaries = new Dictionaries(locale, mainDictionary, contactsDictionary,
- userDictionary, userHistoryDictionary, personalizationDictionary);
+ mDictionaries = new Dictionaries(locale, mainDictionary, subDicts);
}
public void closeDictionaries() {
@@ -323,15 +313,15 @@ public class DictionaryFacilitatorForSuggest {
dictionaries = mDictionaries;
mDictionaries = new Dictionaries();
}
- for (final Dictionary dict : dictionaries.mDictMap.values()) {
- dict.close();
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) {
+ dictionaries.closeDict(dictType);
}
}
// The main dictionary could have been loaded asynchronously. Don't cache the return value
// of this method.
public boolean hasInitializedMainDictionary() {
- final Dictionary mainDict = mDictionaries.getMainDict();
+ final Dictionary mainDict = mDictionaries.getDict(Dictionary.TYPE_MAIN);
return mainDict != null && mainDict.isInitialized();
}
@@ -408,7 +398,7 @@ public class DictionaryFacilitatorForSuggest {
// consolidation is done.
// TODO: Remove this hack when ready.
final int lowerCaseFreqInMainDict = dictionaries.hasDict(Dictionary.TYPE_MAIN) ?
- dictionaries.getMainDict().getFrequency(suggestionLowerCase) :
+ dictionaries.getDict(Dictionary.TYPE_MAIN).getFrequency(suggestionLowerCase) :
Dictionary.NOT_A_PROBABILITY;
if (maxFreq < lowerCaseFreqInMainDict
&& lowerCaseFreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) {
@@ -439,12 +429,11 @@ public class DictionaryFacilitatorForSuggest {
final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
final int sessionId, final ArrayList<SuggestedWordInfo> rawSuggestions) {
final Dictionaries dictionaries = mDictionaries;
- final Map<String, Dictionary> dictMap = dictionaries.mDictMap;
final SuggestionResults suggestionResults =
new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS);
final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
- for (final String dictType : dictTypesOrderedToGetSuggestion) {
- final Dictionary dictionary = dictMap.get(dictType);
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) {
+ final Dictionary dictionary = dictionaries.getDict(dictType);
if (null == dictionary) continue;
final ArrayList<SuggestedWordInfo> dictionarySuggestions =
dictionary.getSuggestionsWithSessionId(composer, prevWord, proximityInfo,
@@ -460,11 +449,11 @@ public class DictionaryFacilitatorForSuggest {
}
public boolean isValidMainDictWord(final String word) {
- final Dictionaries dictionaries = mDictionaries;
- if (TextUtils.isEmpty(word) || !dictionaries.hasDict(Dictionary.TYPE_MAIN)) {
+ final Dictionary mainDict = mDictionaries.getDict(Dictionary.TYPE_MAIN);
+ if (TextUtils.isEmpty(word) || mainDict == null) {
return false;
}
- return dictionaries.getMainDict().isValidWord(word);
+ return mainDict.isValidWord(word);
}
public boolean isValidWord(final String word, final boolean ignoreCase) {
@@ -476,8 +465,8 @@ public class DictionaryFacilitatorForSuggest {
return false;
}
final String lowerCasedWord = word.toLowerCase(dictionaries.mLocale);
- final Map<String, Dictionary> dictMap = dictionaries.mDictMap;
- for (final Dictionary dictionary : dictMap.values()) {
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) {
+ final Dictionary dictionary = dictionaries.getDict(dictType);
// Ideally the passed map would come out of a {@link java.util.concurrent.Future} and
// would be immutable once it's finished initializing, but concretely a null test is
// probably good enough for the time being.
@@ -495,8 +484,10 @@ public class DictionaryFacilitatorForSuggest {
return Dictionary.NOT_A_PROBABILITY;
}
int maxFreq = -1;
- final Map<String, Dictionary> dictMap = mDictionaries.mDictMap;
- for (final Dictionary dictionary : dictMap.values()) {
+ final Dictionaries dictionaries = mDictionaries;
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTION) {
+ final Dictionary dictionary = dictionaries.getDict(dictType);
+ if (dictionary == null) continue;
final int tempFreq = dictionary.getFrequency(word);
if (tempFreq >= maxFreq) {
maxFreq = tempFreq;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 550db4a6c..c825ca462 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -97,6 +97,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
private final ReentrantReadWriteLock mLock;
+ private Map<String, String> mAdditionalAttributeMap = null;
+
/* A extension for a binary dictionary file. */
protected static final String DICT_FILE_EXTENSION = ".dict";
@@ -196,6 +198,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
protected Map<String, String> getHeaderAttributeMap() {
HashMap<String, String> attributeMap = new HashMap<String, String>();
+ if (mAdditionalAttributeMap != null) {
+ attributeMap.putAll(mAdditionalAttributeMap);
+ }
attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, mDictName);
attributeMap.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, mLocale.toString());
attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY,
@@ -523,17 +528,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
} else if (mBinaryDictionary == null) {
// Otherwise, load the existing dictionary.
loadBinaryDictionaryLocked();
+ if (mBinaryDictionary != null && !(isValidDictionaryLocked()
+ // TODO: remove the check below
+ && matchesExpectedBinaryDictFormatVersionForThisType(
+ mBinaryDictionary.getFormatVersion()))) {
+ // Binary dictionary or its format version is not valid. Regenerate
+ // the dictionary file. writeBinaryDictionary will remove the
+ // existing files if appropriate.
+ createNewDictionaryLocked();
+ }
}
mNeedsToReload = false;
- if (mBinaryDictionary != null && !(isValidDictionaryLocked()
- // TODO: remove the check below
- && matchesExpectedBinaryDictFormatVersionForThisType(
- mBinaryDictionary.getFormatVersion()))) {
- // Binary dictionary or its format version is not valid. Regenerate
- // the dictionary file. writeBinaryDictionary will remove the
- // existing files if appropriate.
- createNewDictionaryLocked();
- }
} finally {
mIsReloading.set(false);
}
@@ -592,6 +597,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
@UsedForTesting
+ public void clearAndFlushDictionaryWithAdditionalAttributes(
+ final Map<String, String> attributeMap) {
+ mAdditionalAttributeMap = attributeMap;
+ clear();
+ }
+
public void dumpAllWordsForDebug() {
reloadDictionaryIfRequired();
asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e5dcb12ae..d64a1a6f7 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -55,7 +55,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.accessibility.AccessibilityUtils;
-import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
@@ -1002,10 +1001,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
LatinImeLogger.commit();
mKeyboardSwitcher.onHideWindow();
- if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
- AccessibleKeyboardViewProxy.getInstance().onHideWindow();
- }
-
if (TRACE) Debug.stopMethodTracing();
if (isShowingOptionDialog()) {
mOptionsDialog.dismiss();
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index b21f30087..e1cda696c 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -28,6 +28,7 @@ import android.provider.UserDictionary.Words;
import android.text.TextUtils;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.UserDictionaryCompatUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -50,23 +51,15 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
// to auto-correct, so we set this to the highest frequency that won't, i.e. 14.
private static final int USER_DICT_SHORTCUT_FREQUENCY = 14;
- // TODO: use Words.SHORTCUT when we target JellyBean or above
- final static String SHORTCUT = "shortcut";
- private static final String[] PROJECTION_QUERY;
- static {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- PROJECTION_QUERY = new String[] {
- Words.WORD,
- SHORTCUT,
- Words.FREQUENCY,
- };
- } else {
- PROJECTION_QUERY = new String[] {
- Words.WORD,
- Words.FREQUENCY,
- };
- }
- }
+ private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] {
+ Words.WORD,
+ Words.SHORTCUT,
+ Words.FREQUENCY,
+ };
+ private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] {
+ Words.WORD,
+ Words.FREQUENCY,
+ };
private static final String NAME = "userunigram";
@@ -74,17 +67,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
final private String mLocale;
final private boolean mAlsoUseMoreRestrictiveLocales;
- public UserBinaryDictionary(final Context context, final Locale locale) {
- this(context, locale, false /* alsoUseMoreRestrictiveLocales */, null /* dictFile */);
- }
-
- public UserBinaryDictionary(final Context context, final Locale locale, final File dictFile) {
- this(context, locale, false /* alsoUseMoreRestrictiveLocales */, dictFile);
- }
-
- public UserBinaryDictionary(final Context context, final Locale locale,
- final boolean alsoUseMoreRestrictiveLocales, final File dictFile) {
- this(context, locale, alsoUseMoreRestrictiveLocales, dictFile, NAME);
+ private UserBinaryDictionary(final Context context, final Locale locale, final File dictFile) {
+ this(context, locale, false /* alsoUseMoreRestrictiveLocales */, dictFile, NAME);
}
protected UserBinaryDictionary(final Context context, final Locale locale,
@@ -121,6 +105,12 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
reloadDictionaryIfRequired();
}
+ @UsedForTesting
+ public static UserBinaryDictionary getDictionary(final Context context, final Locale locale,
+ final File dictFile) {
+ return new UserBinaryDictionary(context, locale, dictFile);
+ }
+
@Override
public synchronized void close() {
if (mObserver != null) {
@@ -179,10 +169,29 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
} else {
requestArguments = localeElements;
}
+ final String requestString = request.toString();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ try {
+ addWordsFromProjectionLocked(PROJECTION_QUERY_WITH_SHORTCUT, requestString,
+ requestArguments);
+ } catch (IllegalArgumentException e) {
+ // This may happen on some non-compliant devices where the declared API is JB+ but
+ // the SHORTCUT column is not present for some reason.
+ addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
+ requestArguments);
+ }
+ } else {
+ addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
+ requestArguments);
+ }
+ }
+
+ private void addWordsFromProjectionLocked(final String[] query, String request,
+ final String[] requestArguments) throws IllegalArgumentException {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), requestArguments, null);
+ Words.CONTENT_URI, query, request, requestArguments, null);
addWordsLocked(cursor);
} catch (final SQLiteException e) {
Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
@@ -239,7 +248,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
if (cursor == null) return;
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
- final int indexShortcut = hasShortcutColumn ? cursor.getColumnIndex(SHORTCUT) : 0;
+ final int indexShortcut = hasShortcutColumn ? cursor.getColumnIndex(Words.SHORTCUT) : 0;
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
while (!cursor.isAfterLast()) {
final String word = cursor.getString(indexWord);
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index d2100d415..75432fbac 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -784,11 +784,11 @@ public final class InputLogic {
// TODO: remove this argument
final LatinIME.UIHandler handler) {
final int codePoint = inputTransaction.mEvent.mCodePoint;
+ final SettingsValues settingsValues = inputTransaction.mSettingsValues;
boolean didAutoCorrect = false;
// We avoid sending spaces in languages without spaces if we were composing.
final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint
- && !inputTransaction.mSettingsValues.mSpacingAndPunctuations
- .mCurrentLanguageHasSpaces
+ && !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
&& mWordComposer.isComposingWord();
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
// If we are in the middle of a recorrection, we need to commit the recorrection
@@ -798,13 +798,13 @@ public final class InputLogic {
}
// isComposingWord() may have changed since we stored wasComposing
if (mWordComposer.isComposingWord()) {
- if (inputTransaction.mSettingsValues.mCorrectionEnabled) {
+ if (settingsValues.mCorrectionEnabled) {
final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
: StringUtils.newSingleCodePointString(codePoint);
- commitCurrentAutoCorrection(inputTransaction.mSettingsValues, separator, handler);
+ commitCurrentAutoCorrection(settingsValues, separator, handler);
didAutoCorrect = true;
} else {
- commitTyped(inputTransaction.mSettingsValues,
+ commitTyped(settingsValues,
StringUtils.newSingleCodePointString(codePoint));
}
}
@@ -821,20 +821,23 @@ public final class InputLogic {
// Double quotes behave like they are usually preceded by space iff we are
// not inside a double quote or after a digit.
needsPrecedingSpace = !isInsideDoubleQuoteOrAfterDigit;
+ } else if (settingsValues.mSpacingAndPunctuations.isClusteringSymbol(codePoint)
+ && settingsValues.mSpacingAndPunctuations.isClusteringSymbol(
+ mConnection.getCodePointBeforeCursor())) {
+ needsPrecedingSpace = false;
} else {
- needsPrecedingSpace = inputTransaction.mSettingsValues.isUsuallyPrecededBySpace(
- codePoint);
+ needsPrecedingSpace = settingsValues.isUsuallyPrecededBySpace(codePoint);
}
if (needsPrecedingSpace) {
- promotePhantomSpace(inputTransaction.mSettingsValues);
+ promotePhantomSpace(settingsValues);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord());
}
if (!shouldAvoidSendingCode) {
- sendKeyCodePoint(inputTransaction.mSettingsValues, codePoint);
+ sendKeyCodePoint(settingsValues, codePoint);
}
if (Constants.CODE_SPACE == codePoint) {
@@ -852,7 +855,7 @@ public final class InputLogic {
swapSwapperAndSpace(inputTransaction);
mSpaceState = SpaceState.SWAP_PUNCTUATION;
} else if ((SpaceState.PHANTOM == inputTransaction.mSpaceState
- && inputTransaction.mSettingsValues.isUsuallyFollowedBySpace(codePoint))
+ && settingsValues.isUsuallyFollowedBySpace(codePoint))
|| (Constants.CODE_DOUBLE_QUOTE == codePoint
&& isInsideDoubleQuoteOrAfterDigit)) {
// If we are in phantom space state, and the user presses a separator, we want to
diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
index 352288f8b..38c28a734 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
@@ -18,15 +18,11 @@ package com.android.inputmethod.latin.personalization;
import android.content.Context;
-import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.ExpandableBinaryDictionary;
import com.android.inputmethod.latin.makedict.DictionaryHeader;
-import com.android.inputmethod.latin.utils.LanguageModelParam;
import java.io.File;
-import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
@@ -47,8 +43,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
/** The locale for this dictionary. */
public final Locale mLocale;
- private Map<String, String> mAdditionalAttributeMap = null;
-
protected DecayingExpandableBinaryDictionaryBase(final Context context,
final String dictName, final Locale locale, final String dictionaryType,
final File dictFile) {
@@ -72,9 +66,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
@Override
protected Map<String, String> getHeaderAttributeMap() {
final Map<String, String> attributeMap = super.getHeaderAttributeMap();
- if (mAdditionalAttributeMap != null) {
- attributeMap.putAll(mAdditionalAttributeMap);
- }
attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY,
DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY,
@@ -92,13 +83,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
// No initial contents.
}
- @UsedForTesting
- public void clearAndFlushDictionaryWithAdditionalAttributes(
- final Map<String, String> attributeMap) {
- mAdditionalAttributeMap = attributeMap;
- clear();
- }
-
/* package */ void runGCIfRequired() {
runGCIfRequired(false /* mindsBlockByGC */);
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
index 4afd5b4c9..1423fceff 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin.personalization;
import android.content.Context;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Dictionary;
import java.io.File;
@@ -26,14 +27,16 @@ import java.util.Locale;
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) {
- this(context, locale, null /* dictFile */);
+ super(context, getDictName(NAME, locale, null /* dictFile */), locale,
+ Dictionary.TYPE_PERSONALIZATION, null /* dictFile */);
}
- public PersonalizationDictionary(final Context context, final Locale locale,
- final File dictFile) {
- super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_PERSONALIZATION,
- dictFile);
+ @UsedForTesting
+ public static PersonalizationDictionary getDictionary(final Context context,
+ final Locale locale, final File dictFile) {
+ return PersonalizationHelper.getPersonalizationDictionary(context, locale);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
index 8a29c354d..818cd9a5f 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin.personalization;
import android.content.Context;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.ExpandableBinaryDictionary;
@@ -32,14 +33,16 @@ import java.util.Locale;
public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase {
/* package */ static final String NAME = UserHistoryDictionary.class.getSimpleName();
+ // TODO: Make this constructor private
/* package */ UserHistoryDictionary(final Context context, final Locale locale) {
- this(context, locale, null /* dictFile */);
+ super(context, getDictName(NAME, locale, null /* dictFile */), locale,
+ Dictionary.TYPE_USER_HISTORY, null /* dictFile */);
}
- public UserHistoryDictionary(final Context context, final Locale locale,
+ @UsedForTesting
+ public static UserHistoryDictionary getDictionary(final Context context, final Locale locale,
final File dictFile) {
- super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_USER_HISTORY,
- dictFile);
+ return PersonalizationHelper.getUserHistoryDictionary(context, locale);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
index 796921f71..b8d2a2248 100644
--- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -30,6 +30,7 @@ import java.util.Locale;
public final class SpacingAndPunctuations {
private final int[] mSortedSymbolsPrecededBySpace;
private final int[] mSortedSymbolsFollowedBySpace;
+ private final int[] mSortedSymbolsClusteringTogether;
private final int[] mSortedWordConnectors;
public final int[] mSortedWordSeparators;
public final PunctuationSuggestions mSuggestPuncList;
@@ -46,6 +47,8 @@ public final class SpacingAndPunctuations {
// To be able to binary search the code point. See {@link #isUsuallyFollowedBySpace(int)}.
mSortedSymbolsFollowedBySpace = StringUtils.toSortedCodePointArray(
res.getString(R.string.symbols_followed_by_space));
+ mSortedSymbolsClusteringTogether = StringUtils.toSortedCodePointArray(
+ res.getString(R.string.symbols_clustering_together));
// To be able to binary search the code point. See {@link #isWordConnector(int)}.
mSortedWordConnectors = StringUtils.toSortedCodePointArray(
res.getString(R.string.symbols_word_connectors));
@@ -85,6 +88,10 @@ public final class SpacingAndPunctuations {
return Arrays.binarySearch(mSortedSymbolsFollowedBySpace, code) >= 0;
}
+ public boolean isClusteringSymbol(final int code) {
+ return Arrays.binarySearch(mSortedSymbolsClusteringTogether, code) >= 0;
+ }
+
public boolean isSentenceSeparator(final int code) {
return code == mSentenceSeparator;
}