aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/src/com/android/inputmethod/latin/common/Constants.java9
-rw-r--r--common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java38
-rw-r--r--java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java57
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java11
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java39
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java69
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java3
-rw-r--r--java/src/com/android/inputmethod/latin/NgramContext.java30
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java117
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java24
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java11
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java14
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java9
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java24
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SuggestionResults.java14
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java24
-rw-r--r--tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java36
19 files changed, 348 insertions, 189 deletions
diff --git a/common/src/com/android/inputmethod/latin/common/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java
index a860d3560..29cdb8ee6 100644
--- a/common/src/com/android/inputmethod/latin/common/Constants.java
+++ b/common/src/com/android/inputmethod/latin/common/Constants.java
@@ -163,7 +163,6 @@ public final class Constants {
// TODO: replace the following constants with state in InputTransaction?
public static final int NOT_A_COORDINATE = -1;
public static final int SUGGESTION_STRIP_COORDINATE = -2;
- public static final int SPELL_CHECKER_COORDINATE = -3;
public static final int EXTERNAL_KEYBOARD_COORDINATE = -4;
// A hint on how many characters to cache from the TextView. A good value of this is given by
@@ -175,10 +174,12 @@ public final class Constants {
public static final int MAX_CHARACTERS_FOR_RECAPITALIZATION = 1024 * 100;
// Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h
+ // TODO: create a overlay and update the value appropriately for the new decoder.
public static final int DICTIONARY_MAX_WORD_LENGTH = 48;
// (MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1)-gram is supported in Java side. Needs to modify
// MAX_PREV_WORD_COUNT_FOR_N_GRAM in native/jni/src/defines.h for suggestions.
+ // TODO: create a overlay and update the value appropriately for the new decoder.
public static final int MAX_PREV_WORD_COUNT_FOR_N_GRAM = 3;
// Key events coming any faster than this are long-presses.
@@ -214,8 +215,6 @@ public final class Constants {
public static final int CODE_DASH = '-';
public static final int CODE_SINGLE_QUOTE = '\'';
public static final int CODE_DOUBLE_QUOTE = '"';
- public static final int CODE_QUESTION_MARK = '?';
- public static final int CODE_EXCLAMATION_MARK = '!';
public static final int CODE_SLASH = '/';
public static final int CODE_BACKSLASH = '\\';
public static final int CODE_VERTICAL_BAR = '|';
@@ -330,6 +329,10 @@ public final class Constants {
*/
public static final int DEFAULT_GESTURE_POINTS_CAPACITY = 128;
+ public static final int MAX_IME_DECODER_RESULTS = 20;
+ public static final int DECODER_SCORE_SCALAR = 1000000;
+ public static final int DECODER_MAX_SCORE = 1000000000;
+
private Constants() {
// This utility class is not publicly instantiable.
}
diff --git a/common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java b/common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java
new file mode 100644
index 000000000..10974634d
--- /dev/null
+++ b/common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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.common;
+
+/**
+ * Emojis are supplementary characters expressed as a low+high pair. For instance,
+ * the emoji U+1F625 is encoded as "\uD83D\uDE25" in UTF-16, where '\uD83D' is in
+ * the range of [0xd800, 0xdbff] and '\uDE25' is in the range of [0xdc00, 0xdfff].
+ * {@see http://docs.oracle.com/javase/6/docs/api/java/lang/Character.html#unicode}
+ */
+public final class UnicodeSurrogate {
+ private static final char LOW_SURROGATE_MIN = '\uD800';
+ private static final char LOW_SURROGATE_MAX = '\uDBFF';
+ private static final char HIGH_SURROGATE_MIN = '\uDC00';
+ private static final char HIGH_SURROGATE_MAX = '\uDFFF';
+
+ public static boolean isLowSurrogate(final char c) {
+ return c >= LOW_SURROGATE_MIN && c <= LOW_SURROGATE_MAX;
+ }
+
+ public static boolean isHighSurrogate(final char c) {
+ return c >= HIGH_SURROGATE_MIN && c <= HIGH_SURROGATE_MAX;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
index 9ab465207..f4c4f1aab 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
@@ -21,6 +21,7 @@ import static com.android.inputmethod.latin.common.Constants.NOT_A_COORDINATE;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.preference.PreferenceManager;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
@@ -73,6 +74,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
private final int mCategoryPageIndicatorBackground;
private EmojiPalettesAdapter mEmojiPalettesAdapter;
private final EmojiLayoutParams mEmojiLayoutParams;
+ private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener;
private ImageButton mDeleteKey;
private TextView mAlphabetKeyLeft;
@@ -127,6 +129,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
mCategoryPageIndicatorBackground = emojiPalettesViewAttr.getColor(
R.styleable.EmojiPalettesView_categoryPageIndicatorBackground, 0);
emojiPalettesViewAttr.recycle();
+ mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener();
}
@Override
@@ -197,7 +200,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
mDeleteKey = (ImageButton)findViewById(R.id.emoji_keyboard_delete);
mDeleteKey.setBackgroundResource(mFunctionalKeyBackgroundId);
mDeleteKey.setTag(Constants.CODE_DELETE);
- mDeleteKey.setOnTouchListener(this);
+ mDeleteKey.setOnTouchListener(mDeleteKeyOnTouchListener);
// {@link #mAlphabetKeyLeft}, {@link #mAlphabetKeyRight, and spaceKey depend on
// {@link View.OnClickListener} as well as {@link View.OnTouchListener}.
@@ -366,7 +369,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
}
public void startEmojiPalettes(final String switchToAlphaLabel,
- final KeyVisualAttributes keyVisualAttr, final KeyboardIconsSet iconSet) {
+ final KeyVisualAttributes keyVisualAttr,
+ final KeyboardIconsSet iconSet) {
final int deleteIconResId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_DELETE_KEY);
if (deleteIconResId != 0) {
mDeleteKey.setImageResource(deleteIconResId);
@@ -392,6 +396,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
public void setKeyboardActionListener(final KeyboardActionListener listener) {
mKeyboardActionListener = listener;
+ mDeleteKeyOnTouchListener.setKeyboardActionListener(listener);
}
private void updateEmojiCategoryPageIdView() {
@@ -427,4 +432,52 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
mTabHost.setCurrentTab(newTabId);
}
}
+
+ private static class DeleteKeyOnTouchListener implements OnTouchListener {
+ private KeyboardActionListener mKeyboardActionListener =
+ KeyboardActionListener.EMPTY_LISTENER;
+
+ public void setKeyboardActionListener(final KeyboardActionListener listener) {
+ mKeyboardActionListener = listener;
+ }
+
+ @Override
+ public boolean onTouch(final View v, final MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ onTouchDown(v);
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ final float x = event.getX();
+ final float y = event.getY();
+ if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) {
+ // Stop generating key events once the finger moves away from the view area.
+ onTouchCanceled(v);
+ }
+ return true;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ onTouchUp(v);
+ return true;
+ }
+ return false;
+ }
+
+ private void onTouchDown(final View v) {
+ mKeyboardActionListener.onPressKey(Constants.CODE_DELETE,
+ 0 /* repeatCount */, true /* isSinglePointer */);
+ v.setPressed(true /* pressed */);
+ }
+
+ private void onTouchUp(final View v) {
+ mKeyboardActionListener.onCodeInput(Constants.CODE_DELETE,
+ NOT_A_COORDINATE, NOT_A_COORDINATE, false /* isKeyRepeat */);
+ mKeyboardActionListener.onReleaseKey(Constants.CODE_DELETE, false /* withSliding */);
+ v.setPressed(false /* pressed */);
+ }
+
+ private void onTouchCanceled(final View v) {
+ v.setBackgroundColor(Color.TRANSPARENT);
+ }
+ }
} \ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 7d7ed77e7..16dcb3208 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -49,8 +49,7 @@ public abstract class Dictionary {
// Spawned by resuming suggestions. Comes from a span that was in the TextView.
public static final String TYPE_RESUMED = "resumed";
- public static final PhonyDictionary DICTIONARY_RESUMED =
- new PhonyDictionary(TYPE_RESUMED);
+ public static final PhonyDictionary DICTIONARY_RESUMED = new PhonyDictionary(TYPE_RESUMED);
// The following types of dictionary have actual functional instances. We don't need final
// phony dictionary instances for them.
@@ -60,10 +59,6 @@ public abstract class Dictionary {
public static final String TYPE_USER = "user";
// User history dictionary internal to LatinIME.
public static final String TYPE_USER_HISTORY = "history";
- // Personalization dictionary.
- public static final String TYPE_PERSONALIZATION = "personalization";
- // Contextual dictionary.
- public static final String TYPE_CONTEXTUAL = "contextual";
public final String mDictType;
// The locale for this dictionary. May be null if unknown (phony dictionary for example).
public final Locale mLocale;
@@ -76,9 +71,7 @@ public abstract class Dictionary {
TYPE_USER_TYPED,
TYPE_USER,
TYPE_CONTACTS,
- TYPE_USER_HISTORY,
- TYPE_PERSONALIZATION,
- TYPE_CONTEXTUAL));
+ TYPE_USER_HISTORY));
public Dictionary(final String dictType, final Locale locale) {
mDictType = dictType;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index 401b52847..d174b40dd 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -21,6 +21,7 @@ import android.util.Pair;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.utils.SuggestionResults;
@@ -42,6 +43,35 @@ import javax.annotation.Nullable;
* DictionaryFacilitator as a client for interacting with dictionaries.
*/
public interface DictionaryFacilitator {
+
+ public static final String[] ALL_DICTIONARY_TYPES = new String[] {
+ Dictionary.TYPE_MAIN,
+ Dictionary.TYPE_USER_HISTORY,
+ Dictionary.TYPE_USER,
+ Dictionary.TYPE_CONTACTS};
+
+ public static final String[] DYNAMIC_DICTIONARY_TYPES = new String[] {
+ Dictionary.TYPE_USER_HISTORY,
+ Dictionary.TYPE_USER,
+ Dictionary.TYPE_CONTACTS};
+
+ /**
+ * {@link Dictionary#TYPE_USER} is deprecated, except for the spelling service.
+ */
+ public static final String[] DICTIONARY_TYPES_FOR_SPELLING = new String[] {
+ Dictionary.TYPE_MAIN,
+ Dictionary.TYPE_USER_HISTORY,
+ Dictionary.TYPE_USER,
+ Dictionary.TYPE_CONTACTS};
+
+ /**
+ * {@link Dictionary#TYPE_USER} is deprecated, except for the spelling service.
+ */
+ public static final String[] DICTIONARY_TYPES_FOR_SUGGESTIONS = new String[] {
+ Dictionary.TYPE_MAIN,
+ Dictionary.TYPE_USER_HISTORY,
+ Dictionary.TYPE_CONTACTS};
+
/**
* Returns whether this facilitator is exactly for this list of locales.
*
@@ -115,8 +145,6 @@ public interface DictionaryFacilitator {
boolean hasAtLeastOneUninitializedMainDictionary();
- boolean hasPersonalizationDictionary();
-
void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
throws InterruptedException;
@@ -133,9 +161,12 @@ public interface DictionaryFacilitator {
// TODO: Revise the way to fusion suggestion results.
SuggestionResults getSuggestionResults(final WordComposer composer,
final NgramContext ngramContext, final long proximityInfoHandle,
- final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId);
+ final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId,
+ final int inputStyle, final KeyboardLayout keyboardLayout);
+
+ boolean isValidSpellingWord(final String word);
- boolean isValidWord(final String word, final boolean ignoreCase);
+ boolean isValidSuggestionWord(final String word);
int getFrequency(final String word);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index 3c390db75..96603ef20 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -23,6 +23,7 @@ import android.util.Pair;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.latin.NgramContext.WordInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.common.Constants;
@@ -38,7 +39,6 @@ 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.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -78,14 +78,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
private final Object mLock = new Object();
private final DistracterFilter mDistracterFilter;
- private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS =
- new String[] {
- Dictionary.TYPE_MAIN,
- Dictionary.TYPE_USER_HISTORY,
- Dictionary.TYPE_USER,
- Dictionary.TYPE_CONTACTS,
- };
-
public static final Map<String, Class<? extends ExpandableBinaryDictionary>>
DICT_TYPE_TO_CLASS = new HashMap<>();
@@ -99,10 +91,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES =
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 */,
- DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS.length);
-
/**
* Returns whether this facilitator is exactly for this list of locales.
*
@@ -392,8 +380,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
}
if (usePersonalizedDicts) {
subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY);
- subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION);
- subDictTypesToUse.add(Dictionary.TYPE_CONTEXTUAL);
}
// Gather all dictionaries. We'll remove them from the list to clean up later.
@@ -405,7 +391,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
if (null == currentDictionaryGroupForLocale) {
continue;
}
- for (final String dictType : SUB_DICT_TYPES) {
+ for (final String dictType : DYNAMIC_DICTIONARY_TYPES) {
if (currentDictionaryGroupForLocale.hasDict(dictType, account)) {
dictTypeForLocale.add(dictType);
}
@@ -564,7 +550,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
mDictionaryGroups = new DictionaryGroup[] { mMostProbableDictionaryGroup };
}
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ for (final String dictType : ALL_DICTIONARY_TYPES) {
dictionaryGroup.closeDict(dictType);
}
}
@@ -600,16 +586,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
return false;
}
- public boolean hasPersonalizationDictionary() {
- final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
- for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
- if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION, null /* account */)) {
- return true;
- }
- }
- return false;
- }
-
public void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
throws InterruptedException {
mLatchForWaitingLoadingMainDictionaries.await(timeout, unit);
@@ -659,8 +635,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale);
final String secondWord;
if (wasAutoCapitalized) {
- if (isValidWord(word, false /* ignoreCase */)
- && !isValidWord(lowerCasedWord, false /* ignoreCase */)) {
+ if (isValidSuggestionWord(word) && !isValidSuggestionWord(lowerCasedWord)) {
// If the word was auto-capitalized and exists only as a capitalized word in the
// dictionary, then we must not downcase it before registering it. For example,
// the name of the contacts in start-of-sentence position would come here with the
@@ -708,21 +683,21 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
public void removeWordFromPersonalizedDicts(final String word) {
removeWord(Dictionary.TYPE_USER_HISTORY, word);
- removeWord(Dictionary.TYPE_PERSONALIZATION, word);
- removeWord(Dictionary.TYPE_CONTEXTUAL, word);
}
// TODO: Revise the way to fusion suggestion results.
- public SuggestionResults getSuggestionResults(final WordComposer composer,
- final NgramContext ngramContext, final long proximityInfoHandle,
- final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) {
+ @Override
+ public SuggestionResults getSuggestionResults(WordComposer composer,
+ NgramContext ngramContext, long proximityInfoHandle,
+ SettingsValuesForSuggestion settingsValuesForSuggestion, int sessionId,
+ int inputStyle, KeyboardLayout keyboardLayout) {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
final SuggestionResults suggestionResults = new SuggestionResults(
SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext());
final float[] weightOfLangModelVsSpatialModel =
new float[] { Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL };
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ for (final String dictType : DICTIONARY_TYPES_FOR_SUGGESTIONS) {
final Dictionary dictionary = dictionaryGroup.getDict(dictType);
if (null == dictionary) continue;
final float weightForLocale = composer.isBatchMode()
@@ -742,7 +717,15 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
return suggestionResults;
}
- public boolean isValidWord(final String word, final boolean ignoreCase) {
+ public boolean isValidSpellingWord(final String word) {
+ return isValidWord(word, DICTIONARY_TYPES_FOR_SPELLING);
+ }
+
+ public boolean isValidSuggestionWord(final String word) {
+ return isValidWord(word, DICTIONARY_TYPES_FOR_SUGGESTIONS);
+ }
+
+ private boolean isValidWord(final String word, final String[] dictionariesToCheck) {
if (TextUtils.isEmpty(word)) {
return false;
}
@@ -751,15 +734,13 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
if (dictionaryGroup.mLocale == null) {
continue;
}
- final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale);
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ for (final String dictType : dictionariesToCheck) {
final Dictionary dictionary = dictionaryGroup.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.
if (null == dictionary) continue;
- if (dictionary.isValidWord(word)
- || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
+ if (dictionary.isValidWord(word)) {
return true;
}
}
@@ -775,7 +756,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
int maxFreq = Dictionary.NOT_A_PROBABILITY;
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ for (final String dictType : ALL_DICTIONARY_TYPES) {
final Dictionary dictionary = dictionaryGroup.getDict(dictType);
if (dictionary == null) continue;
final int tempFreq;
@@ -814,10 +795,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
clearSubDictionary(Dictionary.TYPE_USER_HISTORY);
}
- public void clearContextualDictionary() {
- clearSubDictionary(Dictionary.TYPE_CONTEXTUAL);
- }
-
public void dumpDictionaryForDebug(final String dictName) {
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
@@ -835,7 +812,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
final ArrayList<Pair<String, DictionaryStats>> statsOfEnabledSubDicts = new ArrayList<>();
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
- for (final String dictType : SUB_DICT_TYPES) {
+ for (final String dictType : DYNAMIC_DICTIONARY_TYPES) {
final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType);
if (dictionary == null) continue;
statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
index 13bd15101..666813da5 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
@@ -128,7 +128,7 @@ public class DictionaryFacilitatorLruCache {
public DictionaryFacilitator get(final Locale locale) {
DictionaryFacilitator dictionaryFacilitator = mLruCache.get(locale);
if (dictionaryFacilitator != null) {
- // dictionary falicitator for the locale is in the cache.
+ // dictionary facilitator for the locale is in the cache.
return dictionaryFacilitator;
}
synchronized (mLock) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 822700808..9a1df4995 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1520,7 +1520,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard.getProximityInfo(),
- mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback);
+ mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback,
+ keyboard.getKeyboardLayout());
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/NgramContext.java b/java/src/com/android/inputmethod/latin/NgramContext.java
index b47731229..2d66fb000 100644
--- a/java/src/com/android/inputmethod/latin/NgramContext.java
+++ b/java/src/com/android/inputmethod/latin/NgramContext.java
@@ -22,6 +22,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.StringUtils;
+import java.util.ArrayList;
import java.util.Arrays;
import javax.annotation.Nonnull;
@@ -38,6 +39,10 @@ public class NgramContext {
public static final NgramContext BEGINNING_OF_SENTENCE =
new NgramContext(WordInfo.BEGINNING_OF_SENTENCE_WORD_INFO);
+ public static final String BEGINNING_OF_SENTENCE_TAG = "<S>";
+
+ public static final String CONTEXT_SEPARATOR = " ";
+
/**
* Word information used to represent previous words information.
*/
@@ -114,6 +119,31 @@ public class NgramContext {
return new NgramContext(prevWordsInfo);
}
+
+ /**
+ * Extracts the previous words context.
+ *
+ * @return a String with the previous words separated by white space.
+ */
+ public String extractPrevWordsContext() {
+ final ArrayList<String> terms = new ArrayList<>();
+ for (int i = mPrevWordsInfo.length - 1; i >= 0; --i) {
+ if (mPrevWordsInfo[i] != null && mPrevWordsInfo[i].isValid()) {
+ final NgramContext.WordInfo wordInfo = mPrevWordsInfo[i];
+ if (wordInfo.mIsBeginningOfSentence) {
+ terms.add(BEGINNING_OF_SENTENCE_TAG);
+ } else {
+ final String term = wordInfo.mWord.toString();
+ if (!term.isEmpty()) {
+ terms.add(term);
+ }
+ }
+ }
+ }
+ return terms.size() == 0 ? BEGINNING_OF_SENTENCE_TAG
+ : TextUtils.join(CONTEXT_SEPARATOR, terms);
+ }
+
public boolean isValid() {
return mPrevWordsCount > 0 && mPrevWordsInfo[0].isValid();
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 834f747d9..660a051b9 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -16,14 +16,12 @@
package com.android.inputmethod.latin;
-import android.graphics.Color;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
-import android.text.Spanned;
import android.text.TextUtils;
-import android.text.style.BackgroundColorSpan;
+import android.text.style.CharacterStyle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
@@ -35,6 +33,7 @@ import android.view.inputmethod.InputMethodManager;
import com.android.inputmethod.compat.InputConnectionCompatUtils;
import com.android.inputmethod.latin.common.Constants;
+import com.android.inputmethod.latin.common.UnicodeSurrogate;
import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
@@ -91,16 +90,10 @@ public final class RichInputConnection implements PrivateCommandPerformer {
private final StringBuilder mComposingText = new StringBuilder();
/**
- * This variable is a temporary object used in
- * {@link #commitTextWithBackgroundColor(CharSequence,int,int,int)} to avoid object creation.
+ * This variable is a temporary object used in {@link #commitText(CharSequence,int)}
+ * to avoid object creation.
*/
private SpannableStringBuilder mTempObjectForCommitText = new SpannableStringBuilder();
- /**
- * This variable is used to track whether the last committed text had the background color or
- * not.
- * TODO: Omit this flag if possible.
- */
- private boolean mLastCommittedTextHasBackgroundColor = false;
private final InputMethodService mParent;
InputConnection mIC;
@@ -239,39 +232,18 @@ public final class RichInputConnection implements PrivateCommandPerformer {
// it works, but it's wrong and should be fixed.
mCommittedTextBeforeComposingText.append(mComposingText);
mComposingText.setLength(0);
- // TODO: Clear this flag in setComposingRegion() and setComposingText() as well if needed.
- mLastCommittedTextHasBackgroundColor = false;
if (null != mIC) {
mIC.finishComposingText();
}
}
/**
- * Synonym of {@code commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT}.
+ * Calls {@link InputConnection#commitText(CharSequence, int)}.
+ *
* @param text The text to commit. This may include styles.
- * See {@link InputConnection#commitText(CharSequence, int)}.
* @param newCursorPosition The new cursor position around the text.
- * See {@link InputConnection#commitText(CharSequence, int)}.
*/
public void commitText(final CharSequence text, final int newCursorPosition) {
- commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT, text.length());
- }
-
- /**
- * Calls {@link InputConnection#commitText(CharSequence, int)} with the given background color.
- * @param text The text to commit. This may include styles.
- * See {@link InputConnection#commitText(CharSequence, int)}.
- * @param newCursorPosition The new cursor position around the text.
- * See {@link InputConnection#commitText(CharSequence, int)}.
- * @param color The background color to be attached. Set {@link Color#TRANSPARENT} to disable
- * the background color. Note that this method specifies {@link BackgroundColorSpan} with
- * {@link Spanned#SPAN_COMPOSING} flag, meaning that the background color persists until
- * {@link #finishComposingText()} is called.
- * @param coloredTextLength the length of text, in Java chars, which should be rendered with
- * the given background color.
- */
- public void commitTextWithBackgroundColor(final CharSequence text, final int newCursorPosition,
- final int color, final int coloredTextLength) {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
mCommittedTextBeforeComposingText.append(text);
@@ -281,44 +253,32 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mExpectedSelStart += text.length() - mComposingText.length();
mExpectedSelEnd = mExpectedSelStart;
mComposingText.setLength(0);
- mLastCommittedTextHasBackgroundColor = false;
if (null != mIC) {
- if (color == Color.TRANSPARENT) {
- mIC.commitText(text, newCursorPosition);
- } else {
- mTempObjectForCommitText.clear();
- mTempObjectForCommitText.append(text);
- final BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(color);
- final int spanLength = Math.min(coloredTextLength, text.length());
- mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, spanLength,
- Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- mIC.commitText(mTempObjectForCommitText, newCursorPosition);
- mLastCommittedTextHasBackgroundColor = true;
+ mTempObjectForCommitText.clear();
+ mTempObjectForCommitText.append(text);
+ final CharacterStyle[] spans = mTempObjectForCommitText.getSpans(
+ 0, text.length(), CharacterStyle.class);
+ for (final CharacterStyle span : spans) {
+ final int spanStart = mTempObjectForCommitText.getSpanStart(span);
+ final int spanEnd = mTempObjectForCommitText.getSpanEnd(span);
+ final int spanFlags = mTempObjectForCommitText.getSpanFlags(span);
+ // We have to adjust the end of the span to include an additional character.
+ // This is to avoid splitting a unicode surrogate pair.
+ // See com.android.inputmethod.latin.common.Constants.UnicodeSurrogate
+ // See https://b.corp.google.com/issues/19255233
+ if (0 < spanEnd && spanEnd < mTempObjectForCommitText.length()) {
+ final char spanEndChar = mTempObjectForCommitText.charAt(spanEnd - 1);
+ final char nextChar = mTempObjectForCommitText.charAt(spanEnd);
+ if (UnicodeSurrogate.isLowSurrogate(spanEndChar)
+ && UnicodeSurrogate.isHighSurrogate(nextChar)) {
+ mTempObjectForCommitText.setSpan(span, spanStart, spanEnd + 1, spanFlags);
+ }
+ }
}
+ mIC.commitText(mTempObjectForCommitText, newCursorPosition);
}
}
- /**
- * Removes the background color from the highlighted text if necessary. Should be called while
- * there is no on-going composing text.
- *
- * <p>CAVEAT: This method internally calls {@link InputConnection#finishComposingText()}.
- * Be careful of any unexpected side effects.</p>
- */
- public void removeBackgroundColorFromHighlightedTextIfNecessary() {
- // TODO: We haven't yet full tested if we really need to check this flag or not. Omit this
- // flag if everything works fine without this condition.
- if (!mLastCommittedTextHasBackgroundColor) {
- return;
- }
- if (mComposingText.length() > 0) {
- Log.e(TAG, "clearSpansWithComposingFlags should be called when composing text is " +
- "empty. mComposingText=" + mComposingText);
- return;
- }
- finishComposingText();
- }
-
public CharSequence getSelectedText(final int flags) {
return (null == mIC) ? null : mIC.getSelectedText(flags);
}
@@ -946,8 +906,6 @@ public final class RichInputConnection implements PrivateCommandPerformer {
}
}
- private boolean mCursorAnchorInfoMonitorEnabled = false;
-
/**
* Requests the editor to call back {@link InputMethodManager#updateCursorAnchorInfo}.
* @param enableMonitor {@code true} to request the editor to call back the method whenever the
@@ -962,23 +920,10 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public boolean requestCursorUpdates(final boolean enableMonitor,
final boolean requestImmediateCallback) {
mIC = mParent.getCurrentInputConnection();
- final boolean scheduled;
- if (null != mIC) {
- scheduled = InputConnectionCompatUtils.requestCursorUpdates(mIC, enableMonitor,
- requestImmediateCallback);
- } else {
- scheduled = false;
+ if (mIC == null) {
+ return false;
}
- mCursorAnchorInfoMonitorEnabled = (scheduled && enableMonitor);
- return scheduled;
- }
-
- /**
- * @return {@code true} if the application reported that the monitor mode of
- * {@link InputMethodService#onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo)}
- * is currently enabled.
- */
- public boolean isCursorAnchorInfoMonitorEnabled() {
- return mCursorAnchorInfoMonitorEnabled;
+ return InputConnectionCompatUtils.requestCursorUpdates(
+ mIC, enableMonitor, requestImmediateCallback);
}
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 0bf0f687a..ddb2b5358 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin;
import android.text.TextUtils;
+import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.common.Constants;
@@ -97,14 +98,16 @@ public final class Suggest {
final NgramContext ngramContext, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
final boolean isCorrectionEnabled, final int inputStyle, final int sequenceNumber,
- final OnGetSuggestedWordsCallback callback) {
+ final OnGetSuggestedWordsCallback callback,
+ final KeyboardLayout keyboardLayout) {
if (wordComposer.isBatchMode()) {
getSuggestedWordsForBatchInput(wordComposer, ngramContext, proximityInfo,
- settingsValuesForSuggestion, inputStyle, sequenceNumber, callback);
+ settingsValuesForSuggestion, inputStyle, sequenceNumber, callback,
+ keyboardLayout);
} else {
getSuggestedWordsForNonBatchInput(wordComposer, ngramContext, proximityInfo,
settingsValuesForSuggestion, inputStyle, isCorrectionEnabled,
- sequenceNumber, callback);
+ sequenceNumber, callback, keyboardLayout);
}
}
@@ -163,7 +166,8 @@ public final class Suggest {
final NgramContext ngramContext, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
final int inputStyleIfNotPrediction, final boolean isCorrectionEnabled,
- final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
+ final int sequenceNumber, final OnGetSuggestedWordsCallback callback,
+ final KeyboardLayout keyboardLayout) {
final String typedWordString = wordComposer.getTypedWord();
final int trailingSingleQuotesCount =
StringUtils.getTrailingSingleQuotesCount(typedWordString);
@@ -173,7 +177,8 @@ public final class Suggest {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(),
- settingsValuesForSuggestion, SESSION_ID_TYPING);
+ settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction,
+ keyboardLayout);
final Locale mostProbableLocale = mDictionaryFacilitator.getMostProbableLocale();
final ArrayList<SuggestedWordInfo> suggestionsContainer =
getTransformedSuggestedWordInfoList(wordComposer, suggestionResults,
@@ -270,7 +275,9 @@ public final class Suggest {
hasAutoCorrection = false;
} else {
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
- if (!AutoCorrectionUtils.suggestionExceedsThreshold(
+ if (suggestionResults.mAutocorrectRecommendation) {
+ hasAutoCorrection = true;
+ } else if (!AutoCorrectionUtils.suggestionExceedsThreshold(
firstSuggestion, consideredWord, mAutoCorrectionThreshold)) {
// Score is too low for autocorrect
hasAutoCorrection = false;
@@ -339,10 +346,11 @@ public final class Suggest {
final NgramContext ngramContext, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
final int inputStyle, final int sequenceNumber,
- final OnGetSuggestedWordsCallback callback) {
+ final OnGetSuggestedWordsCallback callback,
+ final KeyboardLayout keyboardLayout) {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(),
- settingsValuesForSuggestion, SESSION_ID_GESTURE);
+ settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle, keyboardLayout);
// For transforming words that don't come from a dictionary, because it's our best bet
final Locale defaultLocale = mDictionaryFacilitator.getMostProbableLocale();
final ArrayList<SuggestedWordInfo> suggestionsContainer =
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index e80e3628f..e6f2f1ec9 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.event.CombinerChain;
import com.android.inputmethod.event.Event;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -464,4 +465,14 @@ public final class WordComposer {
public String getRejectedBatchModeSuggestion() {
return mRejectedBatchModeSuggestion;
}
+
+ @UsedForTesting
+ void addInputPointerForTest(int index, int keyX, int keyY) {
+ mInputPointers.addPointerAt(index, keyX, keyY, 0, 0);
+ }
+
+ @UsedForTesting
+ void setTypedWordCacheForTests(String typedWordCacheForTests) {
+ mTypedWordCache = typedWordCacheForTests;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 18927ce85..9154cc35a 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -32,6 +32,7 @@ import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.compat.SuggestionSpanUtils;
import com.android.inputmethod.event.Event;
import com.android.inputmethod.event.InputTransaction;
+import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.Dictionary;
@@ -474,9 +475,7 @@ public final class InputLogic {
handler.cancelUpdateSuggestionStrip();
++mAutoCommitSequenceNumber;
mConnection.beginBatchEdit();
- if (!mWordComposer.isComposingWord()) {
- mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
- } else {
+ if (mWordComposer.isComposingWord()) {
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
// If we are in the middle of a recorrection, we need to commit the recorrection
// first so that we can insert the batch input at the current cursor position.
@@ -767,10 +766,6 @@ public final class InputLogic {
final InputTransaction inputTransaction,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- if (!mWordComposer.isComposingWord()) {
- mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
- }
-
final int codePoint = event.mCodePoint;
mSpaceState = SpaceState.NONE;
if (inputTransaction.mSettingsValues.isWordSeparator(codePoint)
@@ -2115,7 +2110,8 @@ public final class InputLogic {
public void getSuggestedWords(final SettingsValues settingsValues,
final ProximityInfo proximityInfo, final int keyboardShiftMode, final int inputStyle,
- final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
+ final int sequenceNumber, final OnGetSuggestedWordsCallback callback,
+ final KeyboardLayout keyboardLayout) {
mWordComposer.adviseCapitalizedModeBeforeFetchingSuggestions(
getActualCapsMode(settingsValues, keyboardShiftMode));
mSuggest.getSuggestedWords(mWordComposer,
@@ -2129,7 +2125,7 @@ public final class InputLogic {
new SettingsValuesForSuggestion(settingsValues.mBlockPotentiallyOffensive,
settingsValues.mPhraseGestureEnabled),
settingsValues.mAutoCorrectionEnabledPerUserSettings,
- inputStyle, sequenceNumber, callback);
+ inputStyle, sequenceNumber, callback, keyboardLayout);
}
/**
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 8744020b1..477e5702f 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -27,6 +27,7 @@ import android.view.textservice.SuggestionsInfo;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.DictionaryFacilitator;
@@ -34,6 +35,7 @@ import com.android.inputmethod.latin.DictionaryFacilitatorLruCache;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodSubtype;
+import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
import com.android.inputmethod.latin.utils.ScriptUtils;
@@ -152,14 +154,15 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
try {
DictionaryFacilitator dictionaryFacilitatorForLocale =
mDictionaryFacilitatorCache.get(locale);
- return dictionaryFacilitatorForLocale.isValidWord(word, false /* igroreCase */);
+ return dictionaryFacilitatorForLocale.isValidSpellingWord(word);
} finally {
mSemaphore.release();
}
}
public SuggestionResults getSuggestionResults(final Locale locale, final WordComposer composer,
- final NgramContext ngramContext, final ProximityInfo proximityInfo) {
+ final NgramContext ngramContext, final ProximityInfo proximityInfo,
+ final KeyboardLayout keyboardLayout) {
Integer sessionId = null;
mSemaphore.acquireUninterruptibly();
try {
@@ -168,7 +171,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
mDictionaryFacilitatorCache.get(locale);
return dictionaryFacilitatorForLocale.getSuggestionResults(composer, ngramContext,
proximityInfo.getNativeProximityInfo(), mSettingsValuesForSuggestion,
- sessionId);
+ sessionId, SuggestedWords.INPUT_STYLE_TYPING, keyboardLayout);
} finally {
if (sessionId != null) {
mSessionIdPool.add(sessionId);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 832bfd066..0b5e12f03 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -29,6 +29,7 @@ import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -271,18 +272,21 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
final int[] codePoints = StringUtils.toCodePointArray(text);
final int[] coordinates;
final ProximityInfo proximityInfo;
+ final KeyboardLayout keyboardLayout;
if (null == keyboard) {
coordinates = CoordinateUtils.newCoordinateArray(codePoints.length,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
proximityInfo = null;
+ keyboardLayout = null;
} else {
coordinates = keyboard.getCoordinates(codePoints);
proximityInfo = keyboard.getProximityInfo();
+ keyboardLayout = keyboard.getKeyboardLayout();
}
composer.setComposingWord(codePoints, coordinates);
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
final SuggestionResults suggestionResults = mService.getSuggestionResults(
- mLocale, composer, ngramContext, proximityInfo);
+ mLocale, composer, ngramContext, proximityInfo, keyboardLayout);
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit,
mService.getRecommendedThreshold(), text, suggestionResults);
isInDict = isInDictForAnyCapitalization(text, capitalizeType);
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 56a04a856..09bb03f65 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -38,6 +38,7 @@ import com.android.inputmethod.latin.DictionaryFacilitator;
import com.android.inputmethod.latin.DictionaryFacilitatorLruCache;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.RichInputMethodSubtype;
+import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.WordComposer;
import com.android.inputmethod.latin.common.StringUtils;
@@ -195,8 +196,7 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
mDistractersCache.put(cacheKey, Boolean.TRUE);
return true;
}
- final boolean Word = dictionaryFacilitator.isValidWord(testedWord, false /* ignoreCase */);
- if (Word) {
+ if (dictionaryFacilitator.isValidSuggestionWord(testedWord)) {
// Valid word is not a distracter.
if (DEBUG) {
Log.d(TAG, "isDistracter: false (valid word)");
@@ -252,7 +252,9 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
suggestionResults = dictionaryFacilitator.getSuggestionResults(composer,
NgramContext.EMPTY_PREV_WORDS_INFO,
keyboard.getProximityInfo().getNativeProximityInfo(),
- settingsValuesForSuggestion, 0 /* sessionId */);
+ settingsValuesForSuggestion, 0 /* sessionId */,
+ SuggestedWords.INPUT_STYLE_TYPING,
+ keyboard.getKeyboardLayout());
}
if (suggestionResults.isEmpty()) {
return false;
@@ -288,14 +290,14 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
final Locale locale) {
final DictionaryFacilitator dictionaryFacilitator =
mDictionaryFacilitatorLruCache.get(locale);
- if (dictionaryFacilitator.isValidWord(testedWord, false /* ignoreCase */)) {
+ if (dictionaryFacilitator.isValidSuggestionWord(testedWord)) {
return false;
}
- final String lowerCaseTargetWord = testedWord.toLowerCase(locale);
- if (testedWord.equals(lowerCaseTargetWord)) {
+ final String lowerCaseWord = testedWord.toLowerCase(locale);
+ if (testedWord.equals(lowerCaseWord)) {
return false;
}
- if (dictionaryFacilitator.isValidWord(lowerCaseTargetWord, false /* ignoreCase */)) {
+ if (dictionaryFacilitator.isValidSuggestionWord(lowerCaseWord)) {
return true;
}
if (StringUtils.getCapitalizationType(testedWord) == StringUtils.CAPITALIZE_FIRST
@@ -314,10 +316,10 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
return HandlingType.getHandlingType(false /* shouldBeLowerCased */, false /* isOov */);
}
final boolean shouldBeLowerCased = shouldBeLowerCased(ngramContext, testedWord, locale);
- final String caseModifiedWord =
- shouldBeLowerCased ? testedWord.toLowerCase(locale) : testedWord;
- final boolean isOov = !mDictionaryFacilitatorLruCache.get(locale).isValidWord(
- caseModifiedWord, false /* ignoreCase */);
+ final String caseModifiedWord = shouldBeLowerCased
+ ? testedWord.toLowerCase(locale) : testedWord;
+ final boolean isOov = !mDictionaryFacilitatorLruCache.get(locale).isValidSuggestionWord(
+ caseModifiedWord);
return HandlingType.getHandlingType(shouldBeLowerCased, isOov);
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
index b319aeb8a..10e3994b6 100644
--- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
+++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
@@ -33,14 +33,21 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
// TODO: Instead of a boolean , we may want to include the context of this suggestion results,
// such as {@link NgramContext}.
public final boolean mIsBeginningOfSentence;
+ public final boolean mAutocorrectRecommendation;
private final int mCapacity;
public SuggestionResults(final int capacity, final boolean isBeginningOfSentence) {
- this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence);
+ this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence, false);
}
- private SuggestionResults(final Comparator<SuggestedWordInfo> comparator,
- final int capacity, final boolean isBeginningOfSentence) {
+ public SuggestionResults(final int capacity, final boolean isBeginningOfSentence,
+ final boolean autocorrectRecommendation) {
+ this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence,
+ autocorrectRecommendation);
+ }
+
+ private SuggestionResults(final Comparator<SuggestedWordInfo> comparator, final int capacity,
+ final boolean isBeginningOfSentence, final boolean autocorrectRecommendation) {
super(comparator);
mCapacity = capacity;
if (ProductionFlags.INCLUDE_RAW_SUGGESTIONS) {
@@ -49,6 +56,7 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
mRawSuggestions = null;
}
mIsBeginningOfSentence = isBeginningOfSentence;
+ mAutocorrectRecommendation = autocorrectRecommendation;
}
@Override
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java
index 9aced5cea..733bf96e2 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java
@@ -45,8 +45,10 @@ public class KeyboardLayoutTest {
assertEquals(0, keyboardLayout.getKeyXCoordinates().length);
assertEquals(0, keyboardLayout.getKeyYCoordinates().length);
- Key key1 = new Key("label1", 101, 102, "101", "101hint", 103, 104, 105, 106, 1100, 1101, 2, 2);
- Key key2 = new Key("label2", 201, 202, "201", "201hint", 203, 204, 205, 206, 2100, 2201, 2, 2);
+ Key key1 = new Key("label1", 101, 102, "101", "101hint", 103, 104, 105, 106, 1100, 1101,
+ 10, 10);
+ Key key2 = new Key("label2", 201, 103, "201", "201hint", 203, 204, 205, 206, 2100, 2101,
+ 10, 10);
ArrayList<Key> sortedKeys = new ArrayList<>(2);
sortedKeys.add(key1);
@@ -57,5 +59,23 @@ public class KeyboardLayoutTest {
assertEquals(2, keyboardLayout.getKeyHeights().length);
assertEquals(2, keyboardLayout.getKeyXCoordinates().length);
assertEquals(2, keyboardLayout.getKeyYCoordinates().length);
+
+ assertEquals(102, keyboardLayout.getKeyCodes()[0]);
+ // xCo + horizontalGap/2
+ assertEquals(105 + 5, keyboardLayout.getKeyXCoordinates()[0]);
+ assertEquals(106, keyboardLayout.getKeyYCoordinates()[0]);
+ // width - horizontalGap
+ assertEquals(1100 - 10, keyboardLayout.getKeyWidths()[0]);
+ // height - verticalGap
+ assertEquals(1101 - 10, keyboardLayout.getKeyHeights()[0]);
+
+ assertEquals(103, keyboardLayout.getKeyCodes()[1]);
+ // xCo + horizontalGap/2
+ assertEquals(205 + 5, keyboardLayout.getKeyXCoordinates()[1]);
+ assertEquals(206, keyboardLayout.getKeyYCoordinates()[1]);
+ // width - horizontalGap
+ assertEquals(2100 - 10, keyboardLayout.getKeyWidths()[1]);
+ // height - verticalGap
+ assertEquals(2101 - 10, keyboardLayout.getKeyHeights()[1]);
}
}
diff --git a/tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java b/tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java
new file mode 100644
index 000000000..59bb08292
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.common;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class UnicodeSurrogateTests extends AndroidTestCase {
+
+ public void testIsLowSurrogate() {
+ assertFalse(UnicodeSurrogate.isLowSurrogate('\uD7FF'));
+ assertTrue(UnicodeSurrogate.isLowSurrogate('\uD83D'));
+ assertFalse(UnicodeSurrogate.isLowSurrogate('\uDC00'));
+ }
+
+ public void testIsHighSurrogate() {
+ assertFalse(UnicodeSurrogate.isHighSurrogate('\uDBFF'));
+ assertTrue(UnicodeSurrogate.isHighSurrogate('\uDE25'));
+ assertFalse(UnicodeSurrogate.isHighSurrogate('\uE000'));
+ }
+}