aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values/attrs.xml22
-rw-r--r--java/res/xml/keyboard_set.xml19
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java113
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java32
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java24
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSet.java96
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java48
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java192
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java43
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java2
-rw-r--r--java/src/com/android/inputmethod/latin/ComposingStateManager.java7
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java5
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java3
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java2
-rw-r--r--native/src/correction.cpp57
-rw-r--r--native/src/correction.h49
-rw-r--r--native/src/defines.h5
-rw-r--r--native/src/proximity_info.cpp3
-rw-r--r--native/src/unigram_dictionary.cpp128
-rw-r--r--native/src/unigram_dictionary.h16
-rw-r--r--native/src/words_priority_queue.h2
-rw-r--r--native/src/words_priority_queue_pool.h26
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java2
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTests.java40
24 files changed, 561 insertions, 375 deletions
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 0ae7fa2ab..70fc7f86e 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -242,6 +242,9 @@
<flag name="withIconLeft" value="0x1000" />
<flag name="withIconRight" value="0x2000" />
<flag name="autoXScale" value="0x4000" />
+ <!-- If true, character case of code, altCode, moreKeys, keyOutputText, keyLabel,
+ or keyHintLabel will never be subject to change. -->
+ <flag name="preserveCase" value="0x8000" />
</attr>
<!-- The icon to display on the key instead of the label. -->
<attr name="keyIcon" format="enum">
@@ -294,6 +297,19 @@
</declare-styleable>
<declare-styleable name="Keyboard_Case">
+ <!-- This should be aligned with KeyboardSet_Element's elementName. -->
+ <attr name="keyboardSetElement" format="enum|string">
+ <enum name="alphabet" value="0" />
+ <enum name="alphabetManualShifted" value="1" />
+ <enum name="alphabetAutomaticShifted" value="2" />
+ <enum name="alphabetShiftLocked" value="3" />
+ <enum name="alphabetShiftLockShifted" value="4" />
+ <enum name="symbols" value="5" />
+ <enum name="symbolsShifted" value="6" />
+ <enum name="phone" value="7" />
+ <enum name="phoneShifted" value="8" />
+ <enum name="number" value="9" />
+ </attr>
<!-- This should be aligned with KeyboardId.MODE_* -->
<attr name="mode" format="enum|string">
<enum name="text" value="0" />
@@ -356,10 +372,8 @@
<enum name="phoneShifted" value="8" />
<enum name="number" value="9" />
</attr>
- <attr name="elementKeyboard" format="reference|enum">
- <!-- This should be aligned with KeyboardSet.ELEMENT_KEYBOARD_* -->
- <enum name="autoGenerateFromAlphabet" value="1"/>
- </attr>
+ <attr name="elementKeyboard" format="reference"/>
+ <attr name="elementAutoGenerate" format="boolean" />
<!-- TODO: Add setShifted and setShiftLocked attribute. -->
</declare-styleable>
</resources>
diff --git a/java/res/xml/keyboard_set.xml b/java/res/xml/keyboard_set.xml
index ebdd9902e..27ef316fe 100644
--- a/java/res/xml/keyboard_set.xml
+++ b/java/res/xml/keyboard_set.xml
@@ -23,7 +23,24 @@
latin:keyboardLocale="en_GB,en_US">
<Element
latin:elementName="alphabet"
- latin:elementKeyboard="@xml/kbd_qwerty" />
+ latin:elementKeyboard="@xml/kbd_qwerty"
+ latin:elementAutoGenerate="true" />
+ <Element
+ latin:elementName="alphabetManualShifted"
+ latin:elementKeyboard="@xml/kbd_qwerty"
+ latin:elementAutoGenerate="true" />
+ <Element
+ latin:elementName="alphabetAutomaticShifted"
+ latin:elementKeyboard="@xml/kbd_qwerty"
+ latin:elementAutoGenerate="true" />
+ <Element
+ latin:elementName="alphabetShiftLocked"
+ latin:elementKeyboard="@xml/kbd_qwerty"
+ latin:elementAutoGenerate="true" />
+ <Element
+ latin:elementName="alphabetShiftLockShifted"
+ latin:elementKeyboard="@xml/kbd_qwerty"
+ latin:elementAutoGenerate="true" />
<Element
latin:elementName="symbols"
latin:elementKeyboard="@xml/kbd_symbols" />
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 3a9423f4b..9c495fd5f 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -52,9 +52,9 @@ public class Key {
public final int mAltCode;
/** Label to display */
- public final CharSequence mLabel;
+ public final String mLabel;
/** Hint label to display on the key in conjunction with the label */
- public final CharSequence mHintLabel;
+ public final String mHintLabel;
/** Flags of the label */
private final int mLabelFlags;
private static final int LABEL_FLAGS_ALIGN_LEFT = 0x01;
@@ -71,14 +71,16 @@ public class Key {
private static final int LABEL_FLAGS_WITH_ICON_LEFT = 0x1000;
private static final int LABEL_FLAGS_WITH_ICON_RIGHT = 0x2000;
private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000;
+ private static final int LABEL_FLAGS_PRESERVE_CASE = 0x8000;
- // TODO: These icon references could be int (icon attribute id)
/** Icon to display instead of a label. Icon takes precedence over a label */
+ private final int mIconAttrId;
+ // TODO: Remove this variable.
private Drawable mIcon;
/** Icon for disabled state */
- private Drawable mDisabledIcon;
+ private final int mDisabledIconAttrId;
/** Preview version of the icon, for the preview popup */
- public final Drawable mPreviewIcon;
+ public final int mPreviewIconAttrId;
/** Width of the key, not including the gap */
public final int mWidth;
@@ -187,7 +189,7 @@ public class Key {
/**
* This constructor is being used only for key in popup suggestions pane.
*/
- public Key(Keyboard.Params params, CharSequence label, CharSequence hintLabel, Drawable icon,
+ public Key(Keyboard.Params params, String label, String hintLabel, Drawable icon,
int code, CharSequence outputText, int x, int y, int width, int height) {
mHeight = height - params.mVerticalGap;
mHorizontalGap = params.mHorizontalGap;
@@ -204,9 +206,10 @@ public class Key {
mOutputText = outputText;
mCode = code;
mAltCode = Keyboard.CODE_UNSPECIFIED;
+ mIconAttrId = KeyboardIconsSet.ATTR_UNDEFINED;
mIcon = icon;
- mDisabledIcon = null;
- mPreviewIcon = null;
+ mDisabledIconAttrId = KeyboardIconsSet.ATTR_UNDEFINED;
+ mPreviewIconAttrId = KeyboardIconsSet.ATTR_UNDEFINED;
// Horizontal gap is divided equally to both sides of the key.
mX = x + mHorizontalGap / 2;
mY = y;
@@ -260,19 +263,6 @@ public class Key {
// Update row to have current x coordinate.
row.setXPos(keyXPos + keyWidth);
- final String[] moreKeys = style.getTextArray(keyAttr,
- R.styleable.Keyboard_Key_moreKeys);
- // In Arabic symbol layouts, we'd like to keep digits in more keys regardless of
- // config_digit_more_keys_enabled.
- if (params.mId.isAlphabetKeyboard()
- && !res.getBoolean(R.bool.config_digit_more_keys_enabled)) {
- mMoreKeys = MoreKeySpecParser.filterOut(res, moreKeys, MoreKeySpecParser.DIGIT_FILTER);
- } else {
- mMoreKeys = moreKeys;
- }
- mMaxMoreKeysColumn = style.getInt(keyAttr,
- R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
-
mBackgroundType = style.getInt(keyAttr,
R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
mActionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0);
@@ -282,24 +272,47 @@ public class Key {
R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0);
mVisualInsetsRight = (int) Keyboard.Builder.getDimensionOrFraction(keyAttr,
R.styleable.Keyboard_Key_visualInsetsRight, params.mBaseWidth, 0);
- final int previewIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
+ mPreviewIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED));
- mPreviewIcon = iconsSet.getIconByAttrId(previewIconAttrId);
- final int iconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
+ mIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
R.styleable.Keyboard_Key_keyIcon, KeyboardIconsSet.ICON_UNDEFINED));
- mIcon = iconsSet.getIconByAttrId(iconAttrId);
- final int disabledIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
+ mIcon = iconsSet.getIconByAttrId(mIconAttrId);
+ mDisabledIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED));
- mDisabledIcon = iconsSet.getIconByAttrId(disabledIconAttrId);
- mHintLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
- mLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags, 0);
- mOutputText = style.getText(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
+ final boolean preserveCase = (mLabelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0;
+
+ final String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
+ if (moreKeys != null) {
+ for (int i = 0; i < moreKeys.length; i++) {
+ moreKeys[i] = adjustCaseOfStringForKeyboardId(
+ moreKeys[i], preserveCase, params.mId);
+ }
+ }
+ // TODO: Add new key label flag to control this.
+ // In Arabic symbol layouts, we'd like to keep digits in more keys regardless of
+ // config_digit_more_keys_enabled.
+ if (params.mId.isAlphabetKeyboard()
+ && !res.getBoolean(R.bool.config_digit_more_keys_enabled)) {
+ mMoreKeys = MoreKeySpecParser.filterOut(res, moreKeys, MoreKeySpecParser.DIGIT_FILTER);
+ } else {
+ mMoreKeys = moreKeys;
+ }
+ mMaxMoreKeysColumn = style.getInt(keyAttr,
+ R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
+
+ mLabel = adjustCaseOfStringForKeyboardId(style.getString(
+ keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId);
+ mHintLabel = adjustCaseOfStringForKeyboardId(style.getString(
+ keyAttr, R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId);
+ mOutputText = adjustCaseOfStringForKeyboardId(style.getString(
+ keyAttr, R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId);
// Choose the first letter of the label as primary code if not
// specified.
- final int code = style.getInt(keyAttr, R.styleable.Keyboard_Key_code,
- Keyboard.CODE_UNSPECIFIED);
+ final int code = adjustCaseOfCodeForKeyboardId(style.getInt(
+ keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED), preserveCase,
+ params.mId);
if (code == Keyboard.CODE_UNSPECIFIED && mOutputText == null
&& !TextUtils.isEmpty(mLabel)) {
if (mLabel.length() != 1) {
@@ -312,13 +325,36 @@ public class Key {
} else {
mCode = code;
}
- mAltCode = style.getInt(keyAttr,
- R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED);
+ mAltCode = adjustCaseOfCodeForKeyboardId(style.getInt(keyAttr,
+ R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED), preserveCase,
+ params.mId);
mHashCode = hashCode(this);
keyAttr.recycle();
}
+ private static int adjustCaseOfCodeForKeyboardId(int code, boolean preserveCase,
+ KeyboardId id) {
+ if (!Keyboard.isLetterCode(code) || preserveCase) return code;
+ final String text = new String(new int[] { code } , 0, 1);
+ final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id);
+ return casedText.codePointAt(0);
+ }
+
+ private static String adjustCaseOfStringForKeyboardId(String text, boolean preserveCase,
+ KeyboardId id) {
+ if (text == null || preserveCase) return text;
+ switch (id.mElementId) {
+ case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
+ case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
+ case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
+ case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
+ return text.toUpperCase(id.mLocale);
+ default:
+ return text;
+ }
+ }
+
private static int hashCode(Key key) {
return Arrays.hashCode(new Object[] {
key.mX,
@@ -328,13 +364,15 @@ public class Key {
key.mCode,
key.mLabel,
key.mHintLabel,
+ key.mIconAttrId,
// Key can be distinguishable without the following members.
// key.mAltCode,
// key.mOutputText,
// key.mActionFlags,
// key.mLabelFlags,
// key.mIcon,
- // key.mPreviewIcon,
+ // key.mDisabledIconAttrId,
+ // key.mPreviewIconAttrId,
// key.mBackgroundType,
// key.mHorizontalGap,
// key.mVerticalGap,
@@ -471,8 +509,9 @@ public class Key {
return (mLabelFlags & LABEL_FLAGS_AUTO_X_SCALE) != 0;
}
- public Drawable getIcon() {
- return mEnabled ? mIcon : mDisabledIcon;
+ // TODO: Get rid of this method.
+ public Drawable getIcon(KeyboardIconsSet iconSet) {
+ return mEnabled ? mIcon : iconSet.getIconByAttrId(mDisabledIconAttrId);
}
// TODO: Get rid of this method.
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index c548f1145..abe5b62ee 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -245,10 +245,10 @@ public class Keyboard {
}
// TODO: Remove this method.
- public CharSequence adjustLabelCase(CharSequence label) {
+ public String adjustLabelCase(String label) {
if (mId.isAlphabetKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label)
&& label.length() < 3 && Character.isLowerCase(label.charAt(0))) {
- return label.toString().toUpperCase(mId.mLocale);
+ return label.toUpperCase(mId.mLocale);
}
return label;
}
@@ -293,6 +293,8 @@ public class Keyboard {
public final Set<Key> mShiftLockKeys = new HashSet<Key>();
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
+ public KeyboardSet.KeysCache mKeysCache;
+
public int mMostCommonKeyHeight = 0;
public int mMostCommonKeyWidth = 0;
@@ -361,7 +363,8 @@ public class Keyboard {
clearHistogram();
}
- public void onAddKey(Key key) {
+ public void onAddKey(Key newKey) {
+ final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey;
mKeys.add(key);
updateHistogram(key);
if (key.mCode == Keyboard.CODE_SHIFT) {
@@ -688,6 +691,10 @@ public class Keyboard {
params.mTouchPositionCorrection.load(data);
}
+ public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
+ mParams.mKeysCache = keysCache;
+ }
+
public Builder<KP> load(int xmlId, KeyboardId id) {
mParams.mId = id;
final XmlResourceParser parser = mResources.getXml(xmlId);
@@ -1034,6 +1041,9 @@ public class Keyboard {
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard_Case);
try {
+ final boolean keyboardSetElementMatched = matchTypedValue(a,
+ R.styleable.Keyboard_Case_keyboardSetElement, id.mElementId,
+ KeyboardId.elementIdToName(id.mElementId));
final boolean modeMatched = matchTypedValue(a,
R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
final boolean navigateActionMatched = matchBoolean(a,
@@ -1062,13 +1072,15 @@ public class Keyboard {
R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
final boolean countryCodeMatched = matchString(a,
R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
- final boolean selected = modeMatched && navigateActionMatched
- && passwordInputMatched && hasSettingsKeyMatched && f2KeyModeMatched
- && clobberSettingsKeyMatched && shortcutKeyEnabledMatched
- && hasShortcutKeyMatched && imeActionMatched && localeCodeMatched
- && languageCodeMatched && countryCodeMatched;
-
- if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
+ final boolean selected = keyboardSetElementMatched && modeMatched
+ && navigateActionMatched && passwordInputMatched && hasSettingsKeyMatched
+ && f2KeyModeMatched && clobberSettingsKeyMatched
+ && shortcutKeyEnabledMatched && hasShortcutKeyMatched && imeActionMatched
+ && localeCodeMatched && languageCodeMatched && countryCodeMatched;
+
+ if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
+ textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement),
+ "keyboardSetElement"),
textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"),
booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index edce4c6e8..8db8c9460 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -58,7 +58,7 @@ public class KeyboardId {
public final int mOrientation;
public final int mWidth;
public final int mMode;
- public final int mElement;
+ public final int mElementId;
private final int mInputType;
private final int mImeOptions;
private final boolean mSettingsKeyEnabled;
@@ -68,14 +68,14 @@ public class KeyboardId {
private final int mHashCode;
- public KeyboardId(int element, Locale locale, int orientation, int width, int mode,
+ public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode,
int inputType, int imeOptions, boolean settingsKeyEnabled, boolean clobberSettingsKey,
boolean shortcutKeyEnabled, boolean hasShortcutKey) {
this.mLocale = locale;
this.mOrientation = orientation;
this.mWidth = width;
this.mMode = mode;
- this.mElement = element;
+ this.mElementId = elementId;
this.mInputType = inputType;
this.mImeOptions = imeOptions;
this.mSettingsKeyEnabled = settingsKeyEnabled;
@@ -89,7 +89,7 @@ public class KeyboardId {
private static int hashCode(KeyboardId id) {
return Arrays.hashCode(new Object[] {
id.mOrientation,
- id.mElement,
+ id.mElementId,
id.mMode,
id.mWidth,
id.navigateAction(),
@@ -107,7 +107,7 @@ public class KeyboardId {
if (other == this)
return true;
return other.mOrientation == this.mOrientation
- && other.mElement == this.mElement
+ && other.mElementId == this.mElementId
&& other.mMode == this.mMode
&& other.mWidth == this.mWidth
&& other.navigateAction() == this.navigateAction()
@@ -121,19 +121,19 @@ public class KeyboardId {
}
public boolean isAlphabetKeyboard() {
- return mElement < ELEMENT_SYMBOLS;
+ return mElementId < ELEMENT_SYMBOLS;
}
public boolean isSymbolsKeyboard() {
- return mElement == ELEMENT_SYMBOLS || mElement == ELEMENT_SYMBOLS_SHIFTED;
+ return mElementId == ELEMENT_SYMBOLS || mElementId == ELEMENT_SYMBOLS_SHIFTED;
}
public boolean isPhoneKeyboard() {
- return mElement == ELEMENT_PHONE || mElement == ELEMENT_PHONE_SHIFTED;
+ return mElementId == ELEMENT_PHONE || mElementId == ELEMENT_PHONE_SHIFTED;
}
public boolean isPhoneShiftKeyboard() {
- return mElement == ELEMENT_PHONE_SHIFTED;
+ return mElementId == ELEMENT_PHONE_SHIFTED;
}
public boolean navigateAction() {
@@ -188,7 +188,7 @@ public class KeyboardId {
@Override
public String toString() {
return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s]",
- elementToString(mElement),
+ elementIdToName(mElementId),
mLocale,
(mOrientation == 1 ? "port" : "land"), mWidth,
modeName(mMode),
@@ -211,8 +211,8 @@ public class KeyboardId {
&& TextUtils.equals(a.privateImeOptions, b.privateImeOptions);
}
- public static String elementToString(int element) {
- switch (element) {
+ public static String elementIdToName(int elementId) {
+ switch (elementId) {
case ELEMENT_ALPHABET: return "alphabet";
case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted";
case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted";
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index f4602b8fd..cacb8a324 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -22,7 +22,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.Log;
-import android.util.TypedValue;
import android.util.Xml;
import android.view.inputmethod.EditorInfo;
@@ -41,6 +40,7 @@ import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
+import java.util.Map;
/**
* This class represents a set of keyboards. Each of them represents a different keyboard
@@ -55,10 +55,38 @@ public class KeyboardSet {
private static final String TAG_KEYBOARD_SET = TAG;
private static final String TAG_ELEMENT = "Element";
- private static final int ELEMENT_KEYBOARD_AUTO_GENERATE_FROM_ALPHABET = 1;
-
private final Context mContext;
private final Params mParams;
+ private final KeysCache mKeysCache = new KeysCache();
+
+ public static class KeysCache {
+ private final Map<Key, Key> mMap;
+
+ public KeysCache() {
+ mMap = new HashMap<Key, Key>();
+ }
+
+ public Key get(Key key) {
+ final Key existingKey = mMap.get(key);
+ if (existingKey != null) {
+ // Reuse the existing element that equals to "key" without adding "key" to the map.
+ return existingKey;
+ }
+ mMap.put(key, key);
+ return key;
+ }
+ }
+
+ static class KeyboardElement {
+ final int mElementId;
+ final int mLayoutId;
+ final boolean mAutoGenerate;
+ KeyboardElement(int elementId, int layoutId, boolean autoGenerate) {
+ mElementId = elementId;
+ mLayoutId = layoutId;
+ mAutoGenerate = autoGenerate;
+ }
+ }
static class Params {
int mMode;
@@ -72,7 +100,8 @@ public class KeyboardSet {
Locale mLocale;
int mOrientation;
int mWidth;
- final HashMap<Integer, Integer> mElementKeyboards = new HashMap<Integer, Integer>();
+ final Map<Integer, KeyboardElement> mElementKeyboards =
+ new HashMap<Integer, KeyboardElement>();
Params() {}
}
@@ -89,15 +118,15 @@ public class KeyboardSet {
}
public Keyboard getMainKeyboard() {
- return getKeyboard(false, false);
+ return getKeyboard(false, false, false);
}
public Keyboard getSymbolsKeyboard() {
- return getKeyboard(true, false);
+ return getKeyboard(true, false, false);
}
public Keyboard getSymbolsShiftedKeyboard() {
- final Keyboard keyboard = getKeyboard(true, true);
+ final Keyboard keyboard = getKeyboard(true, false, true);
// TODO: Remove this logic once we introduce initial keyboard shift state attribute.
// Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
// sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
@@ -106,22 +135,23 @@ public class KeyboardSet {
return keyboard;
}
- private Keyboard getKeyboard(boolean isSymbols, boolean isShift) {
- final int element = KeyboardSet.getElement(mParams.mMode, isSymbols, isShift);
- // TODO: If xmlId is ELEMENT_KEYBOARD_AUTO_GENERATE_FROM_ALPHABET, auto generate the
- // keyboard based on base main alphabet keyboard considering element.
- final int xmlId = mParams.mElementKeyboards.get(element);
- final KeyboardId id = KeyboardSet.getKeyboardId(element, isSymbols, mParams);
- final Keyboard keyboard = getKeyboard(mContext, xmlId, id);
+ private Keyboard getKeyboard(boolean isSymbols, boolean isShiftLock, boolean isShift) {
+ final int elementId = KeyboardSet.getElementId(
+ mParams.mMode, isSymbols, isShiftLock, isShift);
+ final KeyboardElement keyboardElement = mParams.mElementKeyboards.get(elementId);
+ // TODO: If keyboardElement.mAutoGenerate is true, the keyboard will be auto generated
+ // based on keyboardElement.mKayoutId Keyboard XML definition.
+ final KeyboardId id = KeyboardSet.getKeyboardId(elementId, isSymbols, mParams);
+ final Keyboard keyboard = getKeyboard(mContext, keyboardElement, id);
return keyboard;
}
public KeyboardId getMainKeyboardId() {
- final int element = KeyboardSet.getElement(mParams.mMode, false, false);
- return KeyboardSet.getKeyboardId(element, false, mParams);
+ final int elementId = KeyboardSet.getElementId(mParams.mMode, false, false, false);
+ return KeyboardSet.getKeyboardId(elementId, false, mParams);
}
- private Keyboard getKeyboard(Context context, int xmlId, KeyboardId id) {
+ private Keyboard getKeyboard(Context context, KeyboardElement element, KeyboardId id) {
final Resources res = context.getResources();
final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
Keyboard keyboard = (ref == null) ? null : ref.get();
@@ -130,7 +160,10 @@ public class KeyboardSet {
try {
final Keyboard.Builder<Keyboard.Params> builder =
new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params());
- builder.load(xmlId, id);
+ if (element.mAutoGenerate) {
+ builder.setAutoGenerate(mKeysCache);
+ }
+ builder.load(element.mLayoutId, id);
builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
keyboard = builder.build();
} finally {
@@ -152,7 +185,8 @@ public class KeyboardSet {
return keyboard;
}
- private static int getElement(int mode, boolean isSymbols, boolean isShift) {
+ private static int getElementId(int mode, boolean isSymbols, boolean isShiftLock,
+ boolean isShift) {
switch (mode) {
case KeyboardId.MODE_PHONE:
return (isSymbols && isShift)
@@ -164,14 +198,15 @@ public class KeyboardSet {
return isShift
? KeyboardId.ELEMENT_SYMBOLS_SHIFTED : KeyboardId.ELEMENT_SYMBOLS;
}
+ // TODO: Consult isShiftLock and isShift to determine the element.
return KeyboardId.ELEMENT_ALPHABET;
}
}
- private static KeyboardId getKeyboardId(int element, boolean isSymbols, Params params) {
+ private static KeyboardId getKeyboardId(int elementId, boolean isSymbols, Params params) {
final boolean hasShortcutKey = params.mVoiceKeyEnabled
&& (isSymbols != params.mVoiceKeyOnMain);
- return new KeyboardId(element, params.mLocale, params.mOrientation, params.mWidth,
+ return new KeyboardId(elementId, params.mLocale, params.mOrientation, params.mWidth,
params.mMode, params.mInputType, params.mImeOptions, params.mSettingsKeyEnabled,
params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey);
}
@@ -240,7 +275,9 @@ public class KeyboardSet {
try {
parseKeyboardSet(mResources, R.xml.keyboard_set);
} catch (Exception e) {
- //
+ throw new RuntimeException(e.getMessage() + " in "
+ + mResources.getResourceName(R.xml.keyboard_set)
+ + " of locale " + mParams.mLocale);
} finally {
LocaleUtils.setSystemLocale(mResources, savedLocale);
}
@@ -304,15 +341,12 @@ public class KeyboardSet {
final int elementName = a.getInt(
R.styleable.KeyboardSet_Element_elementName, 0);
- final int index = R.styleable.KeyboardSet_Element_elementKeyboard;
- final TypedValue v = a.peekValue(index);
- final int elementKeyboard;
- if (v.type == TypedValue.TYPE_REFERENCE) {
- elementKeyboard = a.getResourceId(index, 0);
- } else {
- elementKeyboard = a.getInt(index, 0);
- }
- mParams.mElementKeyboards.put(elementName, elementKeyboard);
+ final int elementKeyboard = a.getResourceId(
+ R.styleable.KeyboardSet_Element_elementKeyboard, 0);
+ final boolean elementAutoGenerate = a.getBoolean(
+ R.styleable.KeyboardSet_Element_elementAutoGenerate, false);
+ mParams.mElementKeyboards.put(elementName, new KeyboardElement(
+ elementName, elementKeyboard, elementAutoGenerate));
} finally {
a.recycle();
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index abc220e34..afcf51059 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -39,6 +39,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.inputmethod.compat.FrameLayoutCompatUtils;
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
@@ -373,7 +374,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
// Read fraction value in TypedArray as float.
- private static float getRatio(TypedArray a, int index) {
+ /* package */ static float getRatio(TypedArray a, int index) {
return a.getFraction(index, 1000, 1000, 1) / 1000.0f;
}
@@ -519,7 +520,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
// Draw key background.
- /* package */ void onDrawKeyBackground(Key key, Canvas canvas, KeyDrawParams params) {
+ protected void onDrawKeyBackground(Key key, Canvas canvas, KeyDrawParams params) {
final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight
+ params.mPadding.left + params.mPadding.right;
final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom;
@@ -541,8 +542,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
// Draw key top visuals.
- /* package */ void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint,
- KeyDrawParams params) {
+ protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
final int keyHeight = key.mHeight;
final float centerX = keyWidth * 0.5f;
@@ -553,11 +553,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
// Draw key label.
- final Drawable icon = key.getIcon();
+ final Drawable icon = key.getIcon(mKeyboard.mIconsSet);
float positionX = centerX;
if (key.mLabel != null) {
// Switch the character to uppercase if shift is pressed
- final CharSequence label = mKeyboard.adjustLabelCase(key.mLabel);
+ final String label = mKeyboard.adjustLabelCase(key.mLabel);
// For characters, use large font. For labels like "Done", use smaller font.
paint.setTypeface(key.selectTypeface(params.mKeyTextStyle));
final int labelSize = key.selectTextSize(params.mKeyLetterSize,
@@ -639,7 +639,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Draw hint label.
if (key.mHintLabel != null) {
- final CharSequence hint = key.mHintLabel;
+ final String hint = key.mHintLabel;
final int hintColor;
final int hintSize;
if (key.hasHintLabel()) {
@@ -718,7 +718,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
// Draw popup hint "..." at the bottom right corner of the key.
- /* package */ void drawKeyPopupHint(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
+ protected void drawKeyPopupHint(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
final int keyHeight = key.mHeight;
@@ -737,8 +737,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- private static final Rect sTextBounds = new Rect();
-
private static int getCharGeometryCacheKey(char reference, Paint paint) {
final int labelSize = (int)paint.getTextSize();
final Typeface face = paint.getTypeface();
@@ -754,42 +752,45 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- private static float getCharHeight(char[] character, Paint paint) {
+ // Working variable for the following methods.
+ private final Rect mTextBounds = new Rect();
+
+ private float getCharHeight(char[] character, Paint paint) {
final Integer key = getCharGeometryCacheKey(character[0], paint);
final Float cachedValue = sTextHeightCache.get(key);
if (cachedValue != null)
return cachedValue;
- paint.getTextBounds(character, 0, 1, sTextBounds);
- final float height = sTextBounds.height();
+ paint.getTextBounds(character, 0, 1, mTextBounds);
+ final float height = mTextBounds.height();
sTextHeightCache.put(key, height);
return height;
}
- private static float getCharWidth(char[] character, Paint paint) {
+ private float getCharWidth(char[] character, Paint paint) {
final Integer key = getCharGeometryCacheKey(character[0], paint);
final Float cachedValue = sTextWidthCache.get(key);
if (cachedValue != null)
return cachedValue;
- paint.getTextBounds(character, 0, 1, sTextBounds);
- final float width = sTextBounds.width();
+ paint.getTextBounds(character, 0, 1, mTextBounds);
+ final float width = mTextBounds.width();
sTextWidthCache.put(key, width);
return width;
}
- private static float getLabelWidth(CharSequence label, Paint paint) {
- paint.getTextBounds(label.toString(), 0, label.length(), sTextBounds);
- return sTextBounds.width();
+ protected float getLabelWidth(CharSequence label, Paint paint) {
+ paint.getTextBounds(label.toString(), 0, label.length(), mTextBounds);
+ return mTextBounds.width();
}
- public float getDefaultLabelWidth(CharSequence label, Paint paint) {
+ public float getDefaultLabelWidth(String label, Paint paint) {
paint.setTextSize(mKeyDrawParams.mKeyLabelSize);
paint.setTypeface(mKeyDrawParams.mKeyTextStyle);
return getLabelWidth(label, paint);
}
- private static void drawIcon(Canvas canvas, Drawable icon, int x, int y, int width,
+ protected static void drawIcon(Canvas canvas, Drawable icon, int x, int y, int width,
int height) {
canvas.translate(x, y);
icon.setBounds(0, 0, width, height);
@@ -898,9 +899,10 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
previewText.setText(mKeyboard.adjustLabelCase(key.mLabel));
} else {
- final Drawable previewIcon = key.mPreviewIcon;
+ final Drawable previewIcon = mKeyboard.mIconsSet.getIconByAttrId(
+ key.mPreviewIconAttrId);
previewText.setCompoundDrawables(null, null, null,
- previewIcon != null ? previewIcon : key.getIcon());
+ previewIcon != null ? previewIcon : key.getIcon(mKeyboard.mIconsSet));
previewText.setText(null);
}
previewText.setBackgroundDrawable(params.mPreviewBackground);
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index aa0f9751d..f5b282df3 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -20,14 +20,11 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Message;
import android.text.TextUtils;
@@ -54,8 +51,6 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
-import java.util.Arrays;
-import java.util.HashMap;
import java.util.Locale;
import java.util.WeakHashMap;
@@ -72,38 +67,33 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
- /* Space key and its icons, drawables and colors. */
+ // TODO: Kill process when the usability study mode was changed.
+ private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
+
+ /** Listener for {@link KeyboardActionListener}. */
+ private KeyboardActionListener mKeyboardActionListener;
+
+ /* Space key and its icons */
private Key mSpaceKey;
private Drawable mSpaceIcon;
- private final boolean mIsSpacebarTriggeringPopupByLongPress;
- private static final int SPACE_LED_LENGTH_PERCENT = 80;
- private final boolean mAutoCorrectionSpacebarLedEnabled;
- private final Drawable mAutoCorrectionSpacebarLedIcon;
+ // Stuff to draw language name on spacebar.
+ private boolean mNeedsToDisplayLanguage;
+ private Locale mSpacebarLocale;
+ private float mSpacebarTextFadeFactor = 0.0f;
private final float mSpacebarTextRatio;
private float mSpacebarTextSize;
private final int mSpacebarTextColor;
private final int mSpacebarTextShadowColor;
- private final HashMap<Integer, BitmapDrawable> mSpacebarDrawableCache =
- new HashMap<Integer, BitmapDrawable>();
-
- private boolean mAutoCorrectionSpacebarLedOn;
- private boolean mNeedsToDisplayLanguage;
- private Locale mSpacebarLocale;
- private float mSpacebarTextFadeFactor = 0.0f;
-
// Height in space key the language name will be drawn. (proportional to space key height)
- public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
+ private static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
// If the full language name needs to be smaller than this value to be drawn on space key,
// its short language name will be used instead.
private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
-
- private final SuddenJumpingTouchEventHandler mTouchScreenRegulator;
-
- // Timing constants
- private final int mKeyRepeatInterval;
-
- // TODO: Kill process when the usability study mode was changed.
- private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
+ // Stuff to draw auto correction LED on spacebar.
+ private boolean mAutoCorrectionSpacebarLedOn;
+ private final boolean mAutoCorrectionSpacebarLedEnabled;
+ private final Drawable mAutoCorrectionSpacebarLedIcon;
+ private static final int SPACE_LED_LENGTH_PERCENT = 80;
// Mini keyboard
private PopupWindow mMoreKeysWindow;
@@ -111,17 +101,16 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private int mMoreKeysPanelPointerTrackerId;
private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache =
new WeakHashMap<Key, MoreKeysPanel>();
+ private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
- /** Listener for {@link KeyboardActionListener}. */
- private KeyboardActionListener mKeyboardActionListener;
+ private final boolean mIsSpacebarTriggeringPopupByLongPress;
+ private final SuddenJumpingTouchEventHandler mTouchScreenRegulator;
+ protected KeyDetector mKeyDetector;
private boolean mHasDistinctMultitouch;
private int mOldPointerCount = 1;
private Key mOldKey;
- private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
- protected KeyDetector mKeyDetector;
-
// To detect double tap.
protected GestureDetector mGestureDetector;
@@ -134,10 +123,14 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private static final int MSG_IGNORE_DOUBLE_TAP = 3;
private static final int MSG_KEY_TYPED = 4;
+ private final int mKeyRepeatInterval;
private boolean mInKeyRepeat;
public KeyTimerHandler(LatinKeyboardView outerInstance) {
super(outerInstance);
+ // TODO: This should be the attribute of LatinKeyboardView.
+ final Resources res = outerInstance.getContext().getResources();
+ mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
}
@Override
@@ -147,7 +140,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
switch (msg.what) {
case MSG_REPEAT_KEY:
tracker.onRepeatKey(tracker.getKey());
- startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, tracker);
+ startKeyRepeatTimer(mKeyRepeatInterval, tracker);
break;
case MSG_LONGPRESS_KEY:
keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker);
@@ -213,7 +206,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
}
- private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
+ class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
private boolean mProcessingShiftDoubleTapEvent = false;
@Override
@@ -222,7 +215,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard.mId.isAlphabetKeyboard()) {
final int pointerIndex = firstDown.getActionIndex();
final int id = firstDown.getPointerId(pointerIndex);
- final PointerTracker tracker = getPointerTracker(id);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(
+ id, LatinKeyboardView.this);
final Key key = tracker.getKeyOn((int)firstDown.getX(), (int)firstDown.getY());
// If the first down event is on shift key.
if (key != null && key.isShift()) {
@@ -241,7 +235,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final MotionEvent secondDown = secondTap;
final int pointerIndex = secondDown.getActionIndex();
final int id = secondDown.getPointerId(pointerIndex);
- final PointerTracker tracker = getPointerTracker(id);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(
+ id, LatinKeyboardView.this);
final Key key = tracker.getKeyOn((int)secondDown.getX(), (int)secondDown.getY());
// If the second down event is also on shift key.
if (key != null && key.isShift()) {
@@ -268,8 +263,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this);
final Resources res = getResources();
+ // TODO: This should be the attribute of LatinKeyboardView.
mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean(
R.bool.config_show_mini_keyboard_at_touched_point);
+ // TODO: This should be the attribute of LatinKeyboardView.
final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance);
mKeyDetector = new KeyDetector(keyHysteresisDistance);
@@ -280,10 +277,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mHasDistinctMultitouch = context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
- mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
PointerTracker.init(mHasDistinctMultitouch, getContext());
+ // TODO: This should be the attribute of LatinKeyboardView.
final int longPressSpaceKeyTimeout =
res.getInteger(R.integer.config_long_press_space_key_timeout);
mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0);
@@ -360,7 +357,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
mSpacebarLocale = keyboard.mId.mLocale;
- clearSpacebarDrawableCache();
}
/**
@@ -522,10 +518,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
return true;
}
- private PointerTracker getPointerTracker(final int id) {
- return PointerTracker.getPointerTracker(id, this);
- }
-
public boolean isInSlidingKeyInput() {
if (mMoreKeysPanel != null) {
return true;
@@ -609,7 +601,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
if (mKeyTimerHandler.isInKeyRepeat()) {
- final PointerTracker tracker = getPointerTracker(id);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
// Key repeating timer will be canceled if 2 or more keys are in action, and current
// event (UP or DOWN) is non-modifier key.
if (pointerCount > 1 && !tracker.isModifier()) {
@@ -623,7 +615,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
// multi-touch panel.
if (nonDistinctMultitouch) {
// Use only main (id=0) pointer tracker.
- PointerTracker tracker = getPointerTracker(0);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(0, this);
if (pointerCount == 1 && oldPointerCount == 2) {
// Multi-touch to single touch transition.
// Send a down event for the latest pointer if the key is different from the
@@ -652,7 +644,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (action == MotionEvent.ACTION_MOVE) {
for (int i = 0; i < pointerCount; i++) {
- final PointerTracker tracker = getPointerTracker(me.getPointerId(i));
+ final PointerTracker tracker = PointerTracker.getPointerTracker(
+ me.getPointerId(i), this);
final int px, py;
if (mMoreKeysPanel != null
&& tracker.mPointerId == mMoreKeysPanelPointerTrackerId) {
@@ -669,7 +662,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
}
} else {
- getPointerTracker(id).processMotionEvent(action, x, y, eventTime, this);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
+ tracker.processMotionEvent(action, x, y, eventTime, this);
}
return true;
@@ -739,7 +733,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
*/
public boolean dispatchHoverEvent(MotionEvent event) {
if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
- final PointerTracker tracker = getPointerTracker(0);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(0, this);
return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker);
}
@@ -759,44 +753,30 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) {
mSpacebarTextFadeFactor = fadeFactor;
mNeedsToDisplayLanguage = needsToDisplayLanguage;
- updateSpacebarIcon();
invalidateKey(mSpaceKey);
}
public void updateAutoCorrectionState(boolean isAutoCorrection) {
if (!mAutoCorrectionSpacebarLedEnabled) return;
mAutoCorrectionSpacebarLedOn = isAutoCorrection;
- updateSpacebarIcon();
invalidateKey(mSpaceKey);
}
@Override
- /* package */ void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint,
- KeyDrawParams params) {
+ protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
super.onDrawKeyTopVisuals(key, canvas, paint, params);
if (key.mCode == Keyboard.CODE_SPACE) {
+ drawSpacebar(key, canvas, paint);
+
// Whether space key needs to show the "..." popup hint for special purposes
if (mIsSpacebarTriggeringPopupByLongPress
&& Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
- super.drawKeyPopupHint(key, canvas, paint, params);
+ drawKeyPopupHint(key, canvas, paint, params);
}
}
}
- // TODO: Get rid of this method and draw spacebar locale and auto correction spacebar LED
- // in onDrawKeyTopVisuals.
- private void updateSpacebarIcon() {
- if (mSpaceKey == null) return;
- if (mNeedsToDisplayLanguage) {
- mSpaceKey.setIcon(getSpaceDrawable(mSpacebarLocale));
- } else if (mAutoCorrectionSpacebarLedOn) {
- mSpaceKey.setIcon(getSpaceDrawable(null));
- } else {
- mSpaceKey.setIcon(mSpaceIcon);
- }
- }
-
private static int getSpacebarTextColor(int color, float fadeFactor) {
final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor),
Color.red(color), Color.green(color), Color.blue(color));
@@ -804,24 +784,23 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
// Compute width of text with specified text size using paint.
- private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) {
+ private int getTextWidth(Paint paint, String text, float textSize) {
paint.setTextSize(textSize);
- paint.getTextBounds(text, 0, text.length(), bounds);
- return bounds.width();
+ return (int)getLabelWidth(text, paint);
}
// Layout locale language name on spacebar.
- private static String layoutSpacebar(Paint paint, Locale locale, int width,
+ private String layoutLanguageOnSpacebar(Paint paint, Locale locale, int width,
float origTextSize) {
- final Rect bounds = new Rect();
-
+ paint.setTextAlign(Align.CENTER);
+ paint.setTypeface(Typeface.DEFAULT);
// Estimate appropriate language name text size to fit in maxTextWidth.
String language = Utils.getFullDisplayName(locale, true);
- int textWidth = getTextWidth(paint, language, origTextSize, bounds);
+ int textWidth = getTextWidth(paint, language, origTextSize);
// Assuming text width and text size are proportional to each other.
float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
// allow variable text size
- textWidth = getTextWidth(paint, language, textSize, bounds);
+ textWidth = getTextWidth(paint, language, textSize);
// If text size goes too small or text does not fit, use middle or short name
final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
|| (textWidth > width);
@@ -829,7 +808,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final boolean useShortName;
if (useMiddleName) {
language = Utils.getMiddleDisplayLanguage(locale);
- textWidth = getTextWidth(paint, language, origTextSize, bounds);
+ textWidth = getTextWidth(paint, language, origTextSize);
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
|| (textWidth > width);
@@ -839,7 +818,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (useShortName) {
language = Utils.getShortDisplayLanguage(locale);
- textWidth = getTextWidth(paint, language, origTextSize, bounds);
+ textWidth = getTextWidth(paint, language, origTextSize);
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
}
paint.setTextSize(textSize);
@@ -847,50 +826,14 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
return language;
}
- private Integer getSpaceDrawableKey(Locale locale) {
- return Arrays.hashCode(new Object[] {
- locale,
- mAutoCorrectionSpacebarLedOn,
- mSpacebarTextFadeFactor
- });
- }
-
- private void clearSpacebarDrawableCache() {
- for (final BitmapDrawable drawable : mSpacebarDrawableCache.values()) {
- final Bitmap bitmap = drawable.getBitmap();
- bitmap.recycle();
- }
- mSpacebarDrawableCache.clear();
- }
-
- private BitmapDrawable getSpaceDrawable(Locale locale) {
- final Integer hashCode = getSpaceDrawableKey(locale);
- final BitmapDrawable cached = mSpacebarDrawableCache.get(hashCode);
- if (cached != null) {
- return cached;
- }
- final BitmapDrawable drawable = new BitmapDrawable(getResources(), drawSpacebar(
- locale, mAutoCorrectionSpacebarLedOn, mSpacebarTextFadeFactor));
- mSpacebarDrawableCache.put(hashCode, drawable);
- return drawable;
- }
-
- private Bitmap drawSpacebar(Locale inputLocale, boolean isAutoCorrection,
- float textFadeFactor) {
- final int width = mSpaceKey.mWidth;
- final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
- final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(buffer);
- canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
+ private void drawSpacebar(Key key, Canvas canvas, Paint paint) {
+ final int width = key.mWidth;
+ final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : key.mHeight;
// If application locales are explicitly selected.
- if (inputLocale != null) {
- final Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setTextAlign(Align.CENTER);
-
- final String language = layoutSpacebar(paint, inputLocale, width, mSpacebarTextSize);
-
+ if (mNeedsToDisplayLanguage) {
+ final String language = layoutLanguageOnSpacebar(paint, mSpacebarLocale, width,
+ mSpacebarTextSize);
// Draw language text with shadow
// In case there is no space icon, we will place the language text at the center of
// spacebar.
@@ -898,28 +841,25 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final float textHeight = -paint.ascent() + descent;
final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
: height / 2 + textHeight / 2;
- paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, textFadeFactor));
+ paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent - 1, paint);
- paint.setColor(getSpacebarTextColor(mSpacebarTextColor, textFadeFactor));
+ paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent, paint);
}
// Draw the spacebar icon at the bottom
- if (isAutoCorrection) {
+ if (mAutoCorrectionSpacebarLedOn) {
final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100;
final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight();
int x = (width - iconWidth) / 2;
int y = height - iconHeight;
- mAutoCorrectionSpacebarLedIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
- mAutoCorrectionSpacebarLedIcon.draw(canvas);
+ drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight);
} else if (mSpaceIcon != null) {
final int iconWidth = mSpaceIcon.getIntrinsicWidth();
final int iconHeight = mSpaceIcon.getIntrinsicHeight();
int x = (width - iconWidth) / 2;
int y = height - iconHeight;
- mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
- mSpaceIcon.draw(canvas);
+ drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight);
}
- return buffer;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index faea38941..b7215ec1b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -40,8 +40,8 @@ public class KeyStyles {
private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle();
public interface KeyStyle {
- public String[] getTextArray(TypedArray a, int index);
- public CharSequence getText(TypedArray a, int index);
+ public String[] getStringArray(TypedArray a, int index);
+ public String getString(TypedArray a, int index);
public int getInt(TypedArray a, int index, int defaultValue);
public int getFlag(TypedArray a, int index, int defaultValue);
}
@@ -52,13 +52,13 @@ public class KeyStyles {
}
@Override
- public String[] getTextArray(TypedArray a, int index) {
- return parseTextArray(a, index);
+ public String[] getStringArray(TypedArray a, int index) {
+ return parseStringArray(a, index);
}
@Override
- public CharSequence getText(TypedArray a, int index) {
- return a.getText(index);
+ public String getString(TypedArray a, int index) {
+ return a.getString(index);
}
@Override
@@ -71,16 +71,15 @@ public class KeyStyles {
return a.getInt(index, defaultValue);
}
- protected static String[] parseTextArray(TypedArray a, int index) {
+ protected static String[] parseStringArray(TypedArray a, int index) {
if (!a.hasValue(index))
return null;
- final CharSequence text = a.getText(index);
- return parseCsvText(text.toString(), a.getResources(), R.string.english_ime_name);
+ return parseCsvString(a.getString(index), a.getResources(), R.string.english_ime_name);
}
}
/* package for test */
- static String[] parseCsvText(String rawText, Resources res, int packageNameResId) {
+ static String[] parseCsvString(String rawText, Resources res, int packageNameResId) {
final String text = Utils.resolveStringResource(rawText, res, packageNameResId);
final int size = text.length();
if (size == 0) {
@@ -139,15 +138,15 @@ public class KeyStyles {
private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>();
@Override
- public String[] getTextArray(TypedArray a, int index) {
+ public String[] getStringArray(TypedArray a, int index) {
return a.hasValue(index)
- ? super.getTextArray(a, index) : (String[])mAttributes.get(index);
+ ? super.getStringArray(a, index) : (String[])mAttributes.get(index);
}
@Override
- public CharSequence getText(TypedArray a, int index) {
+ public String getString(TypedArray a, int index) {
return a.hasValue(index)
- ? super.getText(a, index) : (CharSequence)mAttributes.get(index);
+ ? super.getString(a, index) : (String)mAttributes.get(index);
}
@Override
@@ -170,10 +169,10 @@ public class KeyStyles {
// TODO: Currently not all Key attributes can be declared as style.
readInt(keyAttr, R.styleable.Keyboard_Key_code);
readInt(keyAttr, R.styleable.Keyboard_Key_altCode);
- readText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
- readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
- readText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
- readTextArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
+ readString(keyAttr, R.styleable.Keyboard_Key_keyLabel);
+ readString(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
+ readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
+ readStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags);
readInt(keyAttr, R.styleable.Keyboard_Key_keyIcon);
readInt(keyAttr, R.styleable.Keyboard_Key_keyIconDisabled);
@@ -183,9 +182,9 @@ public class KeyStyles {
readFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
}
- private void readText(TypedArray a, int index) {
+ private void readString(TypedArray a, int index) {
if (a.hasValue(index))
- mAttributes.put(index, a.getText(index));
+ mAttributes.put(index, a.getString(index));
}
private void readInt(TypedArray a, int index) {
@@ -199,8 +198,8 @@ public class KeyStyles {
mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
}
- private void readTextArray(TypedArray a, int index) {
- final CharSequence[] value = parseTextArray(a, index);
+ private void readStringArray(TypedArray a, int index) {
+ final String[] value = parseStringArray(a, index);
if (value != null)
mAttributes.put(index, value);
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index 09ecbcaa0..bec6ae1cc 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -31,7 +31,7 @@ public class KeyboardIconsSet {
private static final String TAG = KeyboardIconsSet.class.getSimpleName();
public static final int ICON_UNDEFINED = 0;
- private static final int ATTR_UNDEFINED = 0;
+ public static final int ATTR_UNDEFINED = 0;
private final Map<Integer, Drawable> mIcons = new HashMap<Integer, Drawable>();
diff --git a/java/src/com/android/inputmethod/latin/ComposingStateManager.java b/java/src/com/android/inputmethod/latin/ComposingStateManager.java
index 8811f2023..27f509a29 100644
--- a/java/src/com/android/inputmethod/latin/ComposingStateManager.java
+++ b/java/src/com/android/inputmethod/latin/ComposingStateManager.java
@@ -53,6 +53,13 @@ public class ComposingStateManager {
}
}
+ public synchronized boolean isComposing() {
+ // TODO: use the composing flag in WordComposer instead of maintaining it
+ // here separately. Even better, do away with this class and manage the auto
+ // correction indicator in the same place as the suggestions.
+ return mIsComposing;
+ }
+
public synchronized boolean isAutoCorrectionIndicatorOn() {
return mAutoCorrectionIndicatorOn;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 31cbc4ee3..d59497d6a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1702,10 +1702,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (DEBUG) {
Log.d(TAG, "Flip the indicator. " + oldAutoCorrectionIndicator
+ " -> " + newAutoCorrectionIndicator);
- if (newAutoCorrectionIndicator
+ if (mComposingStateManager.isComposing() && newAutoCorrectionIndicator
!= mComposingStateManager.isAutoCorrectionIndicatorOn()) {
- throw new RuntimeException("Couldn't flip the indicator! We are not "
- + "composing a word right now.");
+ throw new RuntimeException("Couldn't flip the indicator!");
}
}
final CharSequence textWithUnderline =
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
index 2bc2cfdf6..db3544987 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
@@ -22,7 +22,8 @@ import com.android.inputmethod.keyboard.ProximityInfo;
import java.util.TreeMap;
public class SpellCheckerProximityInfo {
- final private static int NUL = KeyDetector.NOT_A_CODE;
+ /* public for test */
+ final public static int NUL = KeyDetector.NOT_A_CODE;
// This must be the same as MAX_PROXIMITY_CHARS_SIZE else it will not work inside
// native code - this value is passed at creation of the binary object and reused
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 3d26d972d..f42b8e681 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -72,7 +72,7 @@ public class MoreSuggestions extends Keyboard {
int pos = fromPos, rowStartPos = fromPos;
final int size = Math.min(suggestions.size(), SuggestionsView.MAX_SUGGESTIONS);
while (pos < size) {
- final CharSequence word = suggestions.getWord(pos);
+ final String word = suggestions.getWord(pos).toString();
// TODO: Should take care of text x-scaling.
mWidths[pos] = (int)view.getDefaultLabelWidth(word, paint) + padding;
final int numColumn = pos - rowStartPos + 1;
diff --git a/native/src/correction.cpp b/native/src/correction.cpp
index 63dd283c8..d7d05edc2 100644
--- a/native/src/correction.cpp
+++ b/native/src/correction.cpp
@@ -269,7 +269,7 @@ bool Correction::needsToPrune() const {
// TODO: use edit distance here
return mOutputIndex - 1 >= mMaxDepth || mProximityCount > mMaxEditDistance
// Allow one char longer word for missing character
- || (!mDoAutoCompletion && (mOutputIndex + 1 >= mInputLength));
+ || (!mDoAutoCompletion && (mOutputIndex > mInputLength));
}
void Correction::addCharToCurrentWord(const int32_t c) {
@@ -555,55 +555,6 @@ Correction::CorrectionType Correction::processCharAndCalcState(
Correction::~Correction() {
}
-/////////////////////////
-// static inline utils //
-/////////////////////////
-
-static const int TWO_31ST_DIV_255 = S_INT_MAX / 255;
-static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) {
- return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX);
-}
-
-static const int TWO_31ST_DIV_2 = S_INT_MAX / 2;
-inline static void multiplyIntCapped(const int multiplier, int *base) {
- const int temp = *base;
- if (temp != S_INT_MAX) {
- // Branch if multiplier == 2 for the optimization
- if (multiplier == 2) {
- *base = TWO_31ST_DIV_2 >= temp ? temp << 1 : S_INT_MAX;
- } else {
- // TODO: This overflow check gives a wrong answer when, for example,
- // temp = 2^16 + 1 and multiplier = 2^17 + 1.
- // Fix this behavior.
- const int tempRetval = temp * multiplier;
- *base = tempRetval >= temp ? tempRetval : S_INT_MAX;
- }
- }
-}
-
-inline static int powerIntCapped(const int base, const int n) {
- if (n <= 0) return 1;
- if (base == 2) {
- return n < 31 ? 1 << n : S_INT_MAX;
- } else {
- int ret = base;
- for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret);
- return ret;
- }
-}
-
-inline static void multiplyRate(const int rate, int *freq) {
- if (*freq != S_INT_MAX) {
- if (*freq > 1000000) {
- *freq /= 100;
- multiplyIntCapped(rate, freq);
- } else {
- multiplyIntCapped(rate, freq);
- *freq /= 100;
- }
- }
-}
-
inline static int getQuoteCount(const unsigned short* word, const int length) {
int quoteCount = 0;
for (int i = 0; i < length; ++i) {
@@ -939,7 +890,11 @@ int Correction::RankingAlgorithm::calcFreqForSplitTwoWords(
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &totalFreq);
}
- multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &totalFreq);
+ if (isSpaceProximity) {
+ multiplyRate(WORDS_WITH_MISTYPED_SPACE_DEMOTION_RATE, &totalFreq);
+ } else {
+ multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &totalFreq);
+ }
if (capitalizedWordDemotion) {
multiplyRate(TWO_WORDS_CAPITALIZED_DEMOTION_RATE, &totalFreq);
diff --git a/native/src/correction.h b/native/src/correction.h
index 0715551d0..b00c8e120 100644
--- a/native/src/correction.h
+++ b/native/src/correction.h
@@ -36,6 +36,55 @@ class Correction {
NOT_ON_TERMINAL
} CorrectionType;
+ /////////////////////////
+ // static inline utils //
+ /////////////////////////
+
+ static const int TWO_31ST_DIV_255 = S_INT_MAX / 255;
+ static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) {
+ return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX);
+ }
+
+ static const int TWO_31ST_DIV_2 = S_INT_MAX / 2;
+ inline static void multiplyIntCapped(const int multiplier, int *base) {
+ const int temp = *base;
+ if (temp != S_INT_MAX) {
+ // Branch if multiplier == 2 for the optimization
+ if (multiplier == 2) {
+ *base = TWO_31ST_DIV_2 >= temp ? temp << 1 : S_INT_MAX;
+ } else {
+ // TODO: This overflow check gives a wrong answer when, for example,
+ // temp = 2^16 + 1 and multiplier = 2^17 + 1.
+ // Fix this behavior.
+ const int tempRetval = temp * multiplier;
+ *base = tempRetval >= temp ? tempRetval : S_INT_MAX;
+ }
+ }
+ }
+
+ inline static int powerIntCapped(const int base, const int n) {
+ if (n <= 0) return 1;
+ if (base == 2) {
+ return n < 31 ? 1 << n : S_INT_MAX;
+ } else {
+ int ret = base;
+ for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret);
+ return ret;
+ }
+ }
+
+ inline static void multiplyRate(const int rate, int *freq) {
+ if (*freq != S_INT_MAX) {
+ if (*freq > 1000000) {
+ *freq /= 100;
+ multiplyIntCapped(rate, freq);
+ } else {
+ multiplyIntCapped(rate, freq);
+ *freq /= 100;
+ }
+ }
+ }
+
Correction(const int typedLetterMultiplier, const int fullWordMultiplier);
void initCorrection(
const ProximityInfo *pi, const int inputLength, const int maxWordLength);
diff --git a/native/src/defines.h b/native/src/defines.h
index 119a7d779..9c2d08777 100644
--- a/native/src/defines.h
+++ b/native/src/defines.h
@@ -169,6 +169,7 @@ static void prof_out(void) {
#define NOT_VALID_WORD -99
#define NOT_A_CHARACTER -1
#define NOT_A_DISTANCE -1
+#define NOT_A_COORDINATE -1
#define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO -2
#define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3
#define NOT_A_INDEX -1
@@ -188,6 +189,7 @@ static void prof_out(void) {
#define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 80
#define WORDS_WITH_MISSING_CHARACTER_DEMOTION_START_POS_10X 12
#define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 58
+#define WORDS_WITH_MISTYPED_SPACE_DEMOTION_RATE 50
#define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75
#define WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE 75
#define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 70
@@ -221,6 +223,9 @@ static void prof_out(void) {
#define MAX_DEPTH_MULTIPLIER 3
+#define FIRST_WORD_INDEX 1
+#define SECOND_WORD_INDEX 2
+
// TODO: Reduce this constant if possible; check the maximum number of umlauts in the same German
// word in the dictionary
#define DEFAULT_MAX_UMLAUT_SEARCH_DEPTH 5
diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp
index b91957c77..e0e938099 100644
--- a/native/src/proximity_info.cpp
+++ b/native/src/proximity_info.cpp
@@ -165,6 +165,9 @@ float ProximityInfo::calculateNormalizedSquaredDistance(
if (!hasSweetSpotData(keyIndex)) {
return NOT_A_DISTANCE_FLOAT;
}
+ if (NOT_A_COORDINATE == mInputXCoordinates[inputIndex]) {
+ return NOT_A_DISTANCE_FLOAT;
+ }
const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(keyIndex, inputIndex);
const float squaredRadius = square(mSweetSpotRadii[keyIndex]);
return squaredDistance / squaredRadius;
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index e998ee486..a7eb4e10d 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -159,19 +159,26 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo,
}
PROF_START(20);
+ if (DEBUG_DICT) {
+ double ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
+ proximityInfo->getPrimaryInputWord(), codesSize, 0, 0, 0);
+ ns += 0;
+ AKLOGI("Max normalized score = %f", ns);
+ }
const int suggestedWordsCount =
queuePool->getMasterQueue()->outputSuggestions(frequencies, outWords);
if (DEBUG_DICT) {
+ double ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
+ proximityInfo->getPrimaryInputWord(), codesSize, 0, 0, 0);
+ ns += 0;
AKLOGI("Returning %d words", suggestedWordsCount);
/// Print the returned words
for (int j = 0; j < suggestedWordsCount; ++j) {
-#ifdef FLAG_DBG
short unsigned int* w = outWords + j * MAX_WORD_LENGTH;
char s[MAX_WORD_LENGTH];
for (int i = 0; i <= MAX_WORD_LENGTH; i++) s[i] = w[i];
AKLOGI("%s %i", s, frequencies[j]);
-#endif
}
}
PROF_END(20);
@@ -205,6 +212,13 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
PROF_START(4);
// Note: This line is intentionally left blank
+ bool hasAutoCorrectionCandidate = false;
+ WordsPriorityQueue* masterQueue = queuePool->getMasterQueue();
+ if (masterQueue->size() > 0) {
+ double nsForMaster = masterQueue->getHighestNormalizedScore(
+ proximityInfo->getPrimaryInputWord(), inputLength, 0, 0, 0);
+ hasAutoCorrectionCandidate = (nsForMaster > START_TWO_WORDS_CORRECTION_THRESHOLD);
+ }
PROF_END(4);
PROF_START(5);
@@ -216,7 +230,8 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
AKLOGI("--- Suggest missing space characters %d", i);
}
getMissingSpaceWords(proximityInfo, xcoordinates, ycoordinates, codes,
- useFullEditDistance, inputLength, i, correction, queuePool);
+ useFullEditDistance, inputLength, i, correction, queuePool,
+ hasAutoCorrectionCandidate);
}
}
PROF_END(5);
@@ -236,7 +251,8 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
}
if (proximityInfo->hasSpaceProximity(x, y)) {
getMistypedSpaceWords(proximityInfo, xcoordinates, ycoordinates, codes,
- useFullEditDistance, inputLength, i, correction, queuePool);
+ useFullEditDistance, inputLength, i, correction, queuePool,
+ hasAutoCorrectionCandidate);
}
}
}
@@ -281,12 +297,12 @@ void UnigramDictionary::getOneWordSuggestions(ProximityInfo *proximityInfo,
WordsPriorityQueuePool *queuePool) {
initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, inputLength, correction);
getSuggestionCandidates(useFullEditDistance, inputLength, correction, queuePool,
- true /* doAutoCompletion */, DEFAULT_MAX_ERRORS);
+ true /* doAutoCompletion */, DEFAULT_MAX_ERRORS, FIRST_WORD_INDEX);
}
void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance,
const int inputLength, Correction *correction, WordsPriorityQueuePool *queuePool,
- const bool doAutoCompletion, const int maxErrors) {
+ const bool doAutoCompletion, const int maxErrors, const int currentWordIndex) {
// TODO: Remove setCorrectionParams
correction->setCorrectionParams(0, 0, 0,
-1 /* spaceProximityPos */, -1 /* missingSpacePos */, useFullEditDistance,
@@ -305,7 +321,8 @@ void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance,
int firstChildPos;
const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos,
- correction, &childCount, &firstChildPos, &siblingPos, queuePool);
+ correction, &childCount, &firstChildPos, &siblingPos, queuePool,
+ currentWordIndex);
// Update next sibling pos
correction->setTreeSiblingPos(outputIndex, siblingPos);
@@ -323,31 +340,32 @@ void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance,
void UnigramDictionary::getMissingSpaceWords(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const bool useFullEditDistance,
const int inputLength, const int missingSpacePos, Correction *correction,
- WordsPriorityQueuePool* queuePool) {
+ WordsPriorityQueuePool* queuePool, const bool hasAutoCorrectionCandidate) {
getSplitTwoWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
useFullEditDistance, inputLength, missingSpacePos, -1/* spaceProximityPos */,
- correction, queuePool);
+ correction, queuePool, hasAutoCorrectionCandidate);
}
void UnigramDictionary::getMistypedSpaceWords(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const bool useFullEditDistance,
const int inputLength, const int spaceProximityPos, Correction *correction,
- WordsPriorityQueuePool* queuePool) {
+ WordsPriorityQueuePool* queuePool, const bool hasAutoCorrectionCandidate) {
getSplitTwoWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
useFullEditDistance, inputLength, -1 /* missingSpacePos */, spaceProximityPos,
- correction, queuePool);
+ correction, queuePool, hasAutoCorrectionCandidate);
}
inline void UnigramDictionary::onTerminal(const int freq,
const TerminalAttributes& terminalAttributes, Correction *correction,
- WordsPriorityQueuePool *queuePool, const bool addToMasterQueue) {
+ WordsPriorityQueuePool *queuePool, const bool addToMasterQueue,
+ const int currentWordIndex) {
const int inputIndex = correction->getInputIndex();
const bool addToSubQueue = inputIndex < SUB_QUEUE_MAX_COUNT;
int wordLength;
unsigned short* wordPointer;
- if (addToMasterQueue) {
+ if ((currentWordIndex == 1) && addToMasterQueue) {
WordsPriorityQueue *masterQueue = queuePool->getMasterQueue();
const int finalFreq = correction->getFinalFreq(freq, &wordPointer, &wordLength);
if (finalFreq != NOT_A_FREQUENCY) {
@@ -376,9 +394,14 @@ inline void UnigramDictionary::onTerminal(const int freq,
// We only allow two words + other error correction for words with SUB_QUEUE_MIN_WORD_LENGTH
// or more length.
if (inputIndex >= SUB_QUEUE_MIN_WORD_LENGTH && addToSubQueue) {
- // TODO: Check the validity of "inputIndex == wordLength"
- //if (addToSubQueue && inputIndex == wordLength) {
- WordsPriorityQueue *subQueue = queuePool->getSubQueue1(inputIndex);
+ WordsPriorityQueue *subQueue;
+ if (currentWordIndex == 1) {
+ subQueue = queuePool->getSubQueue1(inputIndex);
+ } else if (currentWordIndex == 2) {
+ subQueue = queuePool->getSubQueue2(inputIndex);
+ } else {
+ return;
+ }
const int finalFreq = correction->getFinalFreqForSubQueue(freq, &wordPointer, &wordLength,
inputIndex);
addWord(wordPointer, wordLength, finalFreq, subQueue);
@@ -388,17 +411,21 @@ inline void UnigramDictionary::onTerminal(const int freq,
void UnigramDictionary::getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo,
const int *xcoordinates, const int *ycoordinates, const int *codes,
const bool useFullEditDistance, const int inputLength, const int missingSpacePos,
- const int spaceProximityPos, Correction *correction, WordsPriorityQueuePool* queuePool) {
+ const int spaceProximityPos, Correction *correction, WordsPriorityQueuePool* queuePool,
+ const bool hasAutoCorrectionCandidate) {
if (inputLength >= MAX_WORD_LENGTH) return;
if (DEBUG_DICT) {
int inputCount = 0;
if (spaceProximityPos >= 0) ++inputCount;
if (missingSpacePos >= 0) ++inputCount;
assert(inputCount <= 1);
+ // MAX_PROXIMITY_CHARS_SIZE in ProximityInfo.java should be 16
+ assert(MAX_PROXIMITY_CHARS == 16);
}
+ initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
+ inputLength, correction);
WordsPriorityQueue *masterQueue = queuePool->getMasterQueue();
-
const bool isSpaceProximity = spaceProximityPos >= 0;
// First word
@@ -411,26 +438,22 @@ void UnigramDictionary::getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo
if (firstFreq > 0) {
firstOutputWordLength = firstInputWordLength;
firstOutputWord = mWord;
- } else {
- if (masterQueue->size() > 0) {
- double nsForMaster = masterQueue->getHighestNormalizedScore(
- proximityInfo->getPrimaryInputWord(), inputLength, 0, 0, 0);
- if (nsForMaster > START_TWO_WORDS_CORRECTION_THRESHOLD) {
- // Do nothing if the highest suggestion exceeds the threshold.
- return;
- }
- }
+ } else if (!hasAutoCorrectionCandidate) {
WordsPriorityQueue* firstWordQueue = queuePool->getSubQueue1(firstInputWordLength);
- if (firstWordQueue->size() < 1) {
+ if (!firstWordQueue || firstWordQueue->size() < 1) {
return;
}
int score = 0;
const double ns = firstWordQueue->getHighestNormalizedScore(
proximityInfo->getPrimaryInputWord(), firstInputWordLength,
&firstOutputWord, &score, &firstOutputWordLength);
+ if (DEBUG_DICT) {
+ AKLOGI("NS1 = %f, Score = %d", ns, score);
+ }
// Two words correction won't be done if the score of the first word doesn't exceed the
// threshold.
- if (ns < TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD) {
+ if (ns < TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD
+ || firstOutputWordLength < SUB_QUEUE_MIN_WORD_LENGTH) {
return;
}
firstFreq = score >> (firstOutputWordLength
@@ -456,14 +479,6 @@ void UnigramDictionary::getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo
outputWord[firstOutputWordLength] = SPACE;
outputWordLength = firstOutputWordLength + 1;
- //const int outputWordLength = firstOutputWordLength + secondWordLength + 1;
- // Space proximity preparation
- //WordsPriorityQueue *subQueue = queuePool->getSubQueue1();
- //initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, firstOutputWordLength,
- //subQueue, correction);
- //getSuggestionCandidates(useFullEditDistance, firstOutputWordLength, correction, subQueue,
- //false, MAX_ERRORS_FOR_TWO_WORDS);
-
// Second word
const int secondInputWordLength = isSpaceProximity
? (inputLength - spaceProximityPos - 1)
@@ -478,9 +493,42 @@ void UnigramDictionary::getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo
if (secondFreq > 0) {
secondOutputWordLength = secondInputWordLength;
secondOutputWord = mWord;
+ } else if (!hasAutoCorrectionCandidate) {
+ const int offset = secondInputWordStartPos;
+ initSuggestions(proximityInfo, &xcoordinates[offset], &ycoordinates[offset],
+ codes + offset * MAX_PROXIMITY_CHARS, secondInputWordLength, correction);
+ queuePool->clearSubQueue2();
+ getSuggestionCandidates(useFullEditDistance, secondInputWordLength, correction,
+ queuePool, false, MAX_ERRORS_FOR_TWO_WORDS, SECOND_WORD_INDEX);
+ if (DEBUG_DICT) {
+ AKLOGI("Dump second word candidates %d", secondInputWordLength);
+ for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) {
+ queuePool->getSubQueue2(i)->dumpTopWord();
+ }
+ }
+ WordsPriorityQueue* secondWordQueue = queuePool->getSubQueue2(secondInputWordLength);
+ if (!secondWordQueue || secondWordQueue->size() < 1) {
+ return;
+ }
+ int score = 0;
+ const double ns = secondWordQueue->getHighestNormalizedScore(
+ proximityInfo->getPrimaryInputWord(), secondInputWordLength,
+ &secondOutputWord, &score, &secondOutputWordLength);
+ if (DEBUG_DICT) {
+ AKLOGI("NS2 = %f, Score = %d", ns, score);
+ }
+ // Two words correction won't be done if the score of the first word doesn't exceed the
+ // threshold.
+ if (ns < TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD
+ || secondOutputWordLength < SUB_QUEUE_MIN_WORD_LENGTH) {
+ return;
+ }
+ secondFreq = score >> (secondOutputWordLength
+ + TWO_WORDS_PLUS_OTHER_ERROR_CORRECTION_DEMOTION_DIVIDER);
}
if (DEBUG_DICT) {
+ DUMP_WORD(secondOutputWord, secondOutputWordLength);
AKLOGI("Second freq: %d", secondFreq);
}
@@ -742,7 +790,8 @@ int UnigramDictionary::getBigramPosition(int pos, unsigned short *word, int offs
// given level, as output into newCount when traversing this level's parent.
inline bool UnigramDictionary::processCurrentNode(const int initialPos,
Correction *correction, int *newCount,
- int *newChildrenPosition, int *nextSiblingPosition, WordsPriorityQueuePool *queuePool) {
+ int *newChildrenPosition, int *nextSiblingPosition, WordsPriorityQueuePool *queuePool,
+ const int currentWordIndex) {
if (DEBUG_DICT) {
correction->checkState();
}
@@ -823,7 +872,8 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos,
const int childrenAddressPos = BinaryFormat::skipFrequency(flags, pos);
const int attributesPos = BinaryFormat::skipChildrenPosition(flags, childrenAddressPos);
TerminalAttributes terminalAttributes(DICT_ROOT, flags, attributesPos);
- onTerminal(freq, terminalAttributes, correction, queuePool, needsToInvokeOnTerminal);
+ onTerminal(freq, terminalAttributes, correction, queuePool, needsToInvokeOnTerminal,
+ currentWordIndex);
// If there are more chars in this node, then this virtual node has children.
// If we are on the last char, this virtual node has children if this node has.
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index b950971bb..461e73586 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -99,11 +99,13 @@ class UnigramDictionary {
const int inputLength, Correction *correction, WordsPriorityQueuePool* queuePool);
void getSuggestionCandidates(
const bool useFullEditDistance, const int inputLength, Correction *correction,
- WordsPriorityQueuePool* queuePool, const bool doAutoCompletion, const int maxErrors);
+ WordsPriorityQueuePool* queuePool, const bool doAutoCompletion, const int maxErrors,
+ const int currentWordIndex);
void getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo,
const int *xcoordinates, const int *ycoordinates, const int *codes,
const bool useFullEditDistance, const int inputLength, const int spaceProximityPos,
- const int missingSpacePos, Correction *correction, WordsPriorityQueuePool* queuePool);
+ const int missingSpacePos, Correction *correction, WordsPriorityQueuePool* queuePool,
+ const bool hasAutoCorrectionCandidate);
void getSplitTwoWordsSuggestionsOld(ProximityInfo *proximityInfo,
const int *xcoordinates, const int *ycoordinates, const int *codes,
const bool useFullEditDistance, const int inputLength, const int spaceProximityPos,
@@ -111,18 +113,20 @@ class UnigramDictionary {
void getMissingSpaceWords(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const bool useFullEditDistance,
const int inputLength, const int missingSpacePos, Correction *correction,
- WordsPriorityQueuePool* queuePool);
+ WordsPriorityQueuePool* queuePool, const bool hasAutoCorrectionCandidate);
void getMistypedSpaceWords(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const bool useFullEditDistance,
const int inputLength, const int spaceProximityPos, Correction *correction,
- WordsPriorityQueuePool* queuePool);
+ WordsPriorityQueuePool* queuePool, const bool hasAutoCorrectionCandidate);
void onTerminal(const int freq, const TerminalAttributes& terminalAttributes,
- Correction *correction, WordsPriorityQueuePool *queuePool, const bool addToMasterQueue);
+ Correction *correction, WordsPriorityQueuePool *queuePool, const bool addToMasterQueue,
+ const int currentWordIndex);
bool needsToSkipCurrentNode(const unsigned short c,
const int inputIndex, const int skipPos, const int depth);
// Process a node by considering proximity, missing and excessive character
bool processCurrentNode(const int initialPos, Correction *correction, int *newCount,
- int *newChildPosition, int *nextSiblingPosition, WordsPriorityQueuePool *queuePool);
+ int *newChildPosition, int *nextSiblingPosition, WordsPriorityQueuePool *queuePool,
+ const int currentWordIndex);
int getMostFrequentWordLike(const int startInputIndex, const int inputLength,
ProximityInfo *proximityInfo, unsigned short *word);
int getMostFrequentWordLikeInner(const uint16_t* const inWord, const int length,
diff --git a/native/src/words_priority_queue.h b/native/src/words_priority_queue.h
index c85f2b9b3..e8cd983b1 100644
--- a/native/src/words_priority_queue.h
+++ b/native/src/words_priority_queue.h
@@ -137,7 +137,7 @@ class WordsPriorityQueue {
if (size() <= 0) {
return;
}
- DUMP_WORD(mSuggestions.top()->mWord, mSuggestions.top()->mWordLength);
+ DUMP_WORD(mHighestSuggestedWord->mWord, mHighestSuggestedWord->mWordLength);
}
double getHighestNormalizedScore(const unsigned short* before, const int beforeLength,
diff --git a/native/src/words_priority_queue_pool.h b/native/src/words_priority_queue_pool.h
index 5fa254852..599b89711 100644
--- a/native/src/words_priority_queue_pool.h
+++ b/native/src/words_priority_queue_pool.h
@@ -45,15 +45,21 @@ class WordsPriorityQueuePool {
// TODO: Come up with more generic pool
WordsPriorityQueue* getSubQueue1(const int id) {
- if (DEBUG_WORDS_PRIORITY_QUEUE) {
- assert(id >= 0 && id < SUB_QUEUE_MAX_COUNT);
+ if (id < 0 || id >= SUB_QUEUE_MAX_COUNT) {
+ if (DEBUG_WORDS_PRIORITY_QUEUE) {
+ assert(false);
+ }
+ return 0;
}
return mSubQueues1[id];
}
WordsPriorityQueue* getSubQueue2(const int id) {
- if (DEBUG_WORDS_PRIORITY_QUEUE) {
- assert(id >= 0 && id < SUB_QUEUE_MAX_COUNT);
+ if (id < 0 || id >= SUB_QUEUE_MAX_COUNT) {
+ if (DEBUG_WORDS_PRIORITY_QUEUE) {
+ assert(false);
+ }
+ return 0;
}
return mSubQueues2[id];
}
@@ -66,6 +72,18 @@ class WordsPriorityQueuePool {
}
}
+ inline void clearSubQueue1() {
+ for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) {
+ mSubQueues1[i]->clear();
+ }
+ }
+
+ inline void clearSubQueue2() {
+ for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) {
+ mSubQueues2[i]->clear();
+ }
+ }
+
void dumpSubQueue1TopSuggestions() {
AKLOGI("DUMP SUBQUEUE1 TOP SUGGESTIONS");
for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java
index 29881d91c..2ae8027af 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java
@@ -39,7 +39,7 @@ public class KeyStylesTests extends AndroidTestCase {
}
private void assertTextArray(String message, String value, String ... expected) {
- final String actual[] = KeyStyles.parseCsvText(value, mTestResources,
+ final String actual[] = KeyStyles.parseCsvString(value, mTestResources,
R.string.empty_string);
if (expected.length == 0) {
assertNull(message, actual);
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 0d5e42b81..59ca22df4 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -34,6 +34,11 @@ import android.widget.TextView;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
+import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService; // for proximity info
+import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
+
+import java.util.Arrays;
+import java.util.HashMap;
public class InputLogicTests extends ServiceTestCase<LatinIME> {
@@ -42,9 +47,29 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> {
private LatinIME mLatinIME;
private TextView mTextView;
private InputConnection mInputConnection;
+ private HashMap<Integer, int[]> mProximity;
public InputLogicTests() {
super(LatinIME.class);
+ mProximity = createProximity();
+ }
+
+ private static HashMap<Integer, int[]> createProximity() {
+ final HashMap<Integer, int[]> proximity = new HashMap<Integer, int[]>();
+ final int[] testProximity = SpellCheckerProximityInfo.getProximityForScript(
+ AndroidSpellCheckerService.SCRIPT_LATIN);
+ final int ROW_SIZE = SpellCheckerProximityInfo.ROW_SIZE;
+ final int NUL = SpellCheckerProximityInfo.NUL;
+ for (int row = 0; row * ROW_SIZE < testProximity.length; ++row) {
+ final int rowBase = row * ROW_SIZE;
+ int column;
+ for (column = 1; NUL != testProximity[rowBase + column]; ++column) {
+ // Do nothing, just search for a NUL element
+ }
+ proximity.put(testProximity[row * ROW_SIZE],
+ Arrays.copyOfRange(testProximity, rowBase, rowBase + column));
+ }
+ return proximity;
}
// returns the previous setting value
@@ -73,7 +98,9 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> {
mLatinIME.onCreate();
setDebugMode(previousDebugSetting);
final EditorInfo ei = new EditorInfo();
+ ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
final InputConnection ic = mTextView.onCreateInputConnection(ei);
+ ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
final LayoutInflater inflater =
(LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewGroup vg = new FrameLayout(getContext());
@@ -95,7 +122,11 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> {
// to keep these tests as pinpoint as possible and avoid bringing it too many dependencies,
// but keep them in mind if something breaks. Commenting them out as is should work.
//mLatinIME.onPressKey(codePoint);
- mLatinIME.onCodeInput(codePoint, new int[] { codePoint },
+ int[] proximityKeys = mProximity.get(codePoint);
+ if (null == proximityKeys) {
+ proximityKeys = new int[] { codePoint };
+ }
+ mLatinIME.onCodeInput(codePoint, proximityKeys,
KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
//mLatinIME.onReleaseKey(codePoint, false);
@@ -139,4 +170,11 @@ public class InputLogicTests extends ServiceTestCase<LatinIME> {
type(Keyboard.CODE_DELETE);
assertEquals("delete selection", EXPECTED_RESULT, mTextView.getText().toString());
}
+
+ public void testAutoCorrect() {
+ final String STRING_TO_TYPE = "tgis ";
+ final String EXPECTED_RESULT = "this ";
+ type(STRING_TO_TYPE);
+ assertEquals("simple auto-correct", EXPECTED_RESULT, mTextView.getText().toString());
+ }
}