aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java3
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java33
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyStyles.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java37
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardParser.java38
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java81
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java132
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboard.java118
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java18
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java64
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java101
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java66
-rw-r--r--java/src/com/android/inputmethod/latin/CandidateView.java14
-rw-r--r--java/src/com/android/inputmethod/latin/DebugSettings.java10
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java13
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java16
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java116
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java4
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java27
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java79
-rw-r--r--java/src/com/android/inputmethod/latin/UserDictionary.java7
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java62
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java4
-rw-r--r--java/src/com/android/inputmethod/voice/VoiceIMEConnector.java134
26 files changed, 585 insertions, 613 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 23886ad97..7396f0518 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -95,7 +95,7 @@ public class Key {
public boolean mPressed;
/** If this is a sticky key, is it on? */
public boolean mOn;
- /** Key is enabled or not. */
+ /** Key is enabled and responds on press */
public boolean mEnabled = true;
private final static int[] KEY_STATE_NORMAL_ON = {
@@ -226,6 +226,7 @@ public class Key {
mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false);
mModifier = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isModifier, false);
mSticky = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky, false);
+ mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true);
mEdgeFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyEdgeFlags, 0)
| row.mRowEdgeFlags;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index e7a9d8513..1a4f90195 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -17,10 +17,12 @@
package com.android.inputmethod.keyboard;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
public abstract class KeyDetector {
public static final int NOT_A_KEY = -1;
+ public static final int NOT_A_CODE = -1;
protected Keyboard mKeyboard;
@@ -104,8 +106,35 @@ public abstract class KeyDetector {
*
* @param x The x-coordinate of a touch point
* @param y The y-coordinate of a touch point
- * @param allKeys All nearby key indices are returned in this array
+ * @param allCodes All nearby key code except functional key are returned in this array
* @return The nearest key index
*/
- abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys);
+ abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes);
+
+ /**
+ * Compute the most common key width in order to use it as proximity key detection threshold.
+ *
+ * @param keyboard The keyboard to compute the most common key width
+ * @return The most common key width in the keyboard
+ */
+ public static int getMostCommonKeyWidth(final Keyboard keyboard) {
+ if (keyboard == null) return 0;
+ final List<Key> keys = keyboard.getKeys();
+ if (keys == null || keys.size() == 0) return 0;
+ final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
+ int maxCount = 0;
+ int mostCommonWidth = 0;
+ for (final Key key : keys) {
+ final Integer width = key.mWidth + key.mGap;
+ Integer count = histogram.get(width);
+ if (count == null)
+ count = 0;
+ histogram.put(width, ++count);
+ if (count > maxCount) {
+ maxCount = count;
+ mostCommonWidth = width;
+ }
+ }
+ return mostCommonWidth;
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
index 44ec53181..169f2e6c3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
@@ -188,6 +188,7 @@ public class KeyStyles {
readBoolean(keyAttr, R.styleable.Keyboard_Key_isModifier);
readBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky);
readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable);
+ readBoolean(keyAttr, R.styleable.Keyboard_Key_enabled);
}
private void readDrawable(TypedArray a, int index) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index db86740c3..d09f6786e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.Utils;
import android.view.inputmethod.EditorInfo;
@@ -41,29 +42,35 @@ public class KeyboardId {
public final int mMode;
public final int mXmlId;
public final int mColorScheme;
+ public final boolean mPasswordInput;
public final boolean mHasSettingsKey;
public final boolean mVoiceKeyEnabled;
public final boolean mHasVoiceKey;
- public final int mImeOptions;
+ public final int mImeAction;
public final boolean mEnableShiftLock;
public final String mXmlName;
private final int mHashCode;
- public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int mode,
- int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled, boolean hasVoiceKey,
- int imeOptions, boolean enableShiftLock) {
+ public KeyboardId(String xmlName, int xmlId, int colorScheme, Locale locale, int orientation,
+ int mode, EditorInfo attribute, boolean hasSettingsKey, boolean voiceKeyEnabled,
+ boolean hasVoiceKey, boolean enableShiftLock) {
+ final int inputType = (attribute != null) ? attribute.inputType : 0;
+ final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
this.mLocale = locale;
this.mOrientation = orientation;
this.mMode = mode;
this.mXmlId = xmlId;
this.mColorScheme = colorScheme;
+ this.mPasswordInput = Utils.isPasswordInputType(inputType)
+ || Utils.isVisiblePasswordInputType(inputType);
this.mHasSettingsKey = hasSettingsKey;
this.mVoiceKeyEnabled = voiceKeyEnabled;
this.mHasVoiceKey = hasVoiceKey;
- // We are interested only in IME_MASK_ACTION enum value and IME_FLAG_NO_ENTER_ACTION.
- this.mImeOptions = imeOptions
- & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+ // We are interested only in {@link EditorInfo#IME_MASK_ACTION} enum value and
+ // {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION}.
+ this.mImeAction = imeOptions & (
+ EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
this.mEnableShiftLock = enableShiftLock;
this.mXmlName = xmlName;
@@ -73,10 +80,11 @@ public class KeyboardId {
mode,
xmlId,
colorScheme,
+ mPasswordInput,
hasSettingsKey,
voiceKeyEnabled,
hasVoiceKey,
- imeOptions,
+ mImeAction,
enableShiftLock,
});
}
@@ -112,10 +120,11 @@ public class KeyboardId {
&& other.mMode == this.mMode
&& other.mXmlId == this.mXmlId
&& other.mColorScheme == this.mColorScheme
+ && other.mPasswordInput == this.mPasswordInput
&& other.mHasSettingsKey == this.mHasSettingsKey
&& other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
&& other.mHasVoiceKey == this.mHasVoiceKey
- && other.mImeOptions == this.mImeOptions
+ && other.mImeAction == this.mImeAction
&& other.mEnableShiftLock == this.mEnableShiftLock;
}
@@ -126,17 +135,19 @@ public class KeyboardId {
@Override
public String toString() {
- return String.format("[%s.xml %s %s %s imeOptions=%s %s%s%s%s%s]",
+ return String.format("[%s.xml %s %s %s imeAction=%s %s%s%s%s%s%s]",
mXmlName,
mLocale,
(mOrientation == 1 ? "port" : "land"),
modeName(mMode),
- imeOptionsName(mImeOptions),
- colorSchemeName(mColorScheme),
+ imeOptionsName(mImeAction),
+ (mPasswordInput ? " passwordInput" : ""),
(mHasSettingsKey ? " hasSettingsKey" : ""),
(mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
(mHasVoiceKey ? " hasVoiceKey" : ""),
- (mEnableShiftLock ? " enableShiftLock" : ""));
+ (mEnableShiftLock ? " enableShiftLock" : ""),
+ colorSchemeName(mColorScheme)
+ );
}
public static String modeName(int mode) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
index e8324e5fd..df64ad5af 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
@@ -103,7 +103,7 @@ import java.util.List;
*/
public class KeyboardParser {
- private static final String TAG = "KeyboardParser";
+ private static final String TAG = KeyboardParser.class.getSimpleName();
private static final boolean DEBUG = false;
// Keyboard XML Tags
@@ -279,8 +279,8 @@ public class KeyboardParser {
checkEndTag(TAG_KEY, parser);
} else {
Key key = new Key(mResources, row, mCurrentX, mCurrentY, parser, mKeyStyles);
- if (DEBUG) Log.d(TAG, String.format("<%s keyLabel=%s code=%d popupCharacters=%s />",
- TAG_KEY, key.mLabel, key.mCode,
+ if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d popupCharacters=%s />",
+ TAG_KEY, (key.mEnabled ? "" : " disabled"), key.mLabel, key.mCode,
Arrays.toString(key.mPopupCharacters)));
checkEndTag(TAG_KEY, parser);
keys.add(key);
@@ -419,6 +419,8 @@ public class KeyboardParser {
try {
final boolean modeMatched = matchInteger(a,
R.styleable.Keyboard_Case_mode, id.mMode);
+ final boolean passwordInputMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_passwordInput, id.mPasswordInput);
final boolean settingsKeyMatched = matchBoolean(a,
R.styleable.Keyboard_Case_hasSettingsKey, id.mHasSettingsKey);
final boolean voiceEnabledMatched = matchBoolean(a,
@@ -427,24 +429,30 @@ public class KeyboardParser {
R.styleable.Keyboard_Case_hasVoiceKey, id.mHasVoiceKey);
final boolean colorSchemeMatched = matchInteger(viewAttr,
R.styleable.KeyboardView_colorScheme, id.mColorScheme);
- // As noted at KeyboardSwitcher.KeyboardId class, we are interested only in
- // enum value masked by IME_MASK_ACTION and IME_FLAG_NO_ENTER_ACTION. So matching
+ // As noted at {@link KeyboardId} class, we are interested only in enum value masked by
+ // {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and
+ // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching
// this attribute with id.mImeOptions as integer value is enough for our purpose.
- final boolean imeOptionsMatched = matchInteger(a,
- R.styleable.Keyboard_Case_imeOptions, id.mImeOptions);
- final boolean selected = modeMatched && settingsKeyMatched && voiceEnabledMatched
- && voiceKeyMatched && colorSchemeMatched && imeOptionsMatched;
-
- if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s> %s", TAG_CASE,
+ final boolean imeActionMatched = matchInteger(a,
+ R.styleable.Keyboard_Case_imeAction, id.mImeAction);
+ final boolean languageCodeMatched = matchString(a,
+ R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
+ final boolean selected = modeMatched && passwordInputMatched && settingsKeyMatched
+ && voiceEnabledMatched && voiceKeyMatched && colorSchemeMatched
+ && imeActionMatched && languageCodeMatched;
+
+ if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
textAttr(KeyboardId.modeName(
a.getInt(R.styleable.Keyboard_Case_mode, -1)), "mode"),
textAttr(KeyboardId.colorSchemeName(
a.getInt(R.styleable.KeyboardView_colorScheme, -1)), "colorSchemeName"),
+ booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
booleanAttr(a, R.styleable.Keyboard_Case_voiceKeyEnabled, "voiceKeyEnabled"),
booleanAttr(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"),
textAttr(KeyboardId.imeOptionsName(
- a.getInt(R.styleable.Keyboard_Case_imeOptions, -1)), "imeOptions"),
+ a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"),
+ textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), "languageCode"),
Boolean.toString(selected)));
return selected;
@@ -466,6 +474,12 @@ public class KeyboardParser {
return !a.hasValue(index) || a.getBoolean(index, false) == value;
}
+ private static boolean matchString(TypedArray a, int index, String value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for the
+ // attribute.
+ return !a.hasValue(index) || a.getString(index).equals(value);
+ }
+
private boolean parseDefault(XmlResourceParser parser, Row row, List<Key> keys)
throws XmlPullParserException, IOException {
if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT));
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 2648ff3d4..3297dc325 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -28,6 +28,7 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.Log;
import android.view.InflateException;
+import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import java.lang.ref.SoftReference;
@@ -66,8 +67,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
+ // TODO: clean mMode up and use mAttribute instead.
private int mMode = KeyboardId.MODE_TEXT; /* default value */
- private int mImeOptions;
+ private EditorInfo mAttribute;
private boolean mIsSymbols;
/** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
* what user actually typed. */
@@ -128,10 +130,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
final int orientation = res.getConfiguration().orientation;
final int mode = mMode;
final int colorScheme = getColorScheme();
- final boolean hasSettingsKey = mHasSettingsKey;
- final boolean voiceKeyEnabled = mVoiceKeyEnabled;
- final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary;
- final int imeOptions = mImeOptions;
+ final boolean hasVoiceKey = mVoiceKeyEnabled && !mVoiceButtonOnPrimary;
// Note: This comment is only applied for phone number keyboard layout.
// On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
// between "phone keyboard" and "phone symbols keyboard". But on xlarge device,
@@ -140,50 +139,43 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
// respectively here for xlarge device's layout switching.
int xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols;
- mSymbolsId = new KeyboardId(
- res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
- hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+ final String xmlName = res.getResourceEntryName(xmlId);
+ mSymbolsId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
+ mAttribute, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, true);
xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift;
- mSymbolsShiftedId = new KeyboardId(
- res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
- hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+ mSymbolsShiftedId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
+ mAttribute, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, true);
}
private boolean hasVoiceKey(boolean isSymbols) {
return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
}
- public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
+ public void loadKeyboard(int mode, EditorInfo attribute, boolean voiceKeyEnabled,
boolean voiceButtonOnPrimary) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
try {
- if (mInputView == null) return;
- final Keyboard oldKeyboard = mInputView.getKeyboard();
- loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false);
- final Keyboard newKeyboard = mInputView.getKeyboard();
- if (newKeyboard.isAlphaKeyboard()) {
- final boolean localeChanged = (oldKeyboard == null)
- || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
- mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
- }
+ loadKeyboardInternal(mode, attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
} catch (RuntimeException e) {
- Log.w(TAG, e);
- LatinImeLogger.logOnException(mode + "," + imeOptions, e);
+ // Get KeyboardId to record which keyboard has been failed to load.
+ final KeyboardId id = getKeyboardId(mode, attribute, false);
+ Log.w(TAG, "loading keyboard failed: " + id, e);
+ LatinImeLogger.logOnException(id.toString(), e);
}
}
- private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
+ private void loadKeyboardInternal(int mode, EditorInfo attribute, boolean voiceButtonEnabled,
boolean voiceButtonOnPrimary, boolean isSymbols) {
if (mInputView == null) return;
mMode = mode;
- mImeOptions = imeOptions;
+ mAttribute = attribute;
mVoiceKeyEnabled = voiceButtonEnabled;
mVoiceButtonOnPrimary = voiceButtonOnPrimary;
mIsSymbols = isSymbols;
// Update the settings key state because number of enabled IMEs could have been changed
mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
- final KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
+ final KeyboardId id = getKeyboardId(mode, attribute, isSymbols);
final Keyboard oldKeyboard = mInputView.getKeyboard();
if (oldKeyboard != null && oldKeyboard.mId.equals(id))
@@ -192,7 +184,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
makeSymbolsKeyboardIds();
mCurrentId = id;
mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
- mInputView.setKeyboard(getKeyboard(id));
+ setKeyboard(getKeyboard(id));
+ }
+
+ private void setKeyboard(final Keyboard newKeyboard) {
+ final Keyboard oldKeyboard = mInputView.getKeyboard();
+ mInputView.setKeyboard(newKeyboard);
+ final boolean localeChanged = (oldKeyboard == null)
+ || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
+ mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
}
private LatinKeyboard getKeyboard(KeyboardId id) {
@@ -228,7 +228,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return keyboard;
}
- private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
+ private KeyboardId getKeyboardId(int mode, EditorInfo attribute, boolean isSymbols) {
final boolean hasVoiceKey = hasVoiceKey(isSymbols);
final int charColorId = getColorScheme();
final int xmlId;
@@ -260,8 +260,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
final int orientation = res.getConfiguration().orientation;
final Locale locale = mSubtypeSwitcher.getInputLocale();
return new KeyboardId(
- res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, charColorId,
- mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock);
+ res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation, mode,
+ attribute, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, enableShiftLock);
}
public int getKeyboardMode() {
@@ -278,22 +278,19 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public boolean isKeyboardAvailable() {
if (mInputView != null)
- return mInputView.getLatinKeyboard() != null;
+ return mInputView.getKeyboard() != null;
return false;
}
- private LatinKeyboard getLatinKeyboard() {
- if (mInputView != null)
- return mInputView.getLatinKeyboard();
+ public LatinKeyboard getLatinKeyboard() {
+ if (mInputView != null) {
+ final Keyboard keyboard = mInputView.getKeyboard();
+ if (keyboard instanceof LatinKeyboard)
+ return (LatinKeyboard)keyboard;
+ }
return null;
}
- public void setPreferredLetters(int[] frequencies) {
- LatinKeyboard latinKeyboard = getLatinKeyboard();
- if (latinKeyboard != null)
- latinKeyboard.setPreferredLetters(frequencies);
- }
-
public void keyReleased() {
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard != null)
@@ -556,7 +553,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// indicator, we need to call enableShiftLock() and setShiftLocked(false).
keyboard.setShifted(false);
}
- mInputView.setKeyboard(keyboard);
+ setKeyboard(keyboard);
}
public boolean isInMomentaryAutoModeSwitchState() {
@@ -572,7 +569,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
private void toggleKeyboardMode() {
- loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
+ loadKeyboardInternal(mMode, mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
!mIsSymbols);
if (mIsSymbols) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 19f1fa8ee..7fee022e0 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -26,6 +26,7 @@ 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;
@@ -68,8 +69,7 @@ import java.util.WeakHashMap;
* @attr ref R.styleable#KeyboardView_popupLayout
*/
public class KeyboardView extends View implements PointerTracker.UIProxy {
- private static final String TAG = "KeyboardView";
- private static final boolean DEBUG = false;
+ private static final String TAG = KeyboardView.class.getSimpleName();
private static final boolean DEBUG_SHOW_ALIGN = false;
private static final boolean DEBUG_KEYBOARD_GRID = false;
@@ -115,7 +115,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private int[] mOffsetInWindow;
private int mOldPreviewKeyIndex = KeyDetector.NOT_A_KEY;
private boolean mShowPreview = true;
- private boolean mShowTouchPoints = true;
private int mPopupPreviewOffsetX;
private int mPopupPreviewOffsetY;
private int mWindowY;
@@ -158,18 +157,20 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
// Drawing
/** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/
private boolean mDrawPending;
+ /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */
+ private boolean mKeyboardChanged;
/** The dirty region in the keyboard bitmap */
private final Rect mDirtyRect = new Rect();
+ /** The key to invalidate. */
+ private Key mInvalidatedKey;
+ /** The dirty region for single key drawing */
+ private final Rect mInvalidatedKeyRect = new Rect();
/** The keyboard bitmap for faster updates */
private Bitmap mBuffer;
- /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */
- private boolean mKeyboardChanged;
- private Key mInvalidatedKey;
/** The canvas for the above mutable keyboard bitmap */
private Canvas mCanvas;
private final Paint mPaint;
private final Rect mPadding;
- private final Rect mClipRegion = new Rect(0, 0, 0, 0);
// This map caches key label text height in pixel as value and key label text size as map key.
private final HashMap<Integer, Integer> mTextHeightCache = new HashMap<Integer, Integer>();
// Distance from horizontal center of the key, proportional to key label text height and width.
@@ -506,10 +507,9 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
tracker.setKeyboard(keyboard, mKeys, mKeyHysteresisDistance);
}
requestLayout();
- // Hint to reallocate the buffer if the size changed
mKeyboardChanged = true;
invalidateAllKeys();
- computeProximityThreshold(keyboard, mKeys);
+ mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(keyboard));
mMiniKeyboardCache.clear();
}
@@ -601,37 +601,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
}
}
- /**
- * Compute the most common key width and use it as proximity key detection threshold.
- * @param keyboard
- * @param keys
- */
- private void computeProximityThreshold(Keyboard keyboard, Key[] keys) {
- if (keyboard == null || keys == null || keys.length == 0) return;
- final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
- int maxCount = 0;
- int mostCommonWidth = 0;
- for (Key key : keys) {
- final Integer width = key.mWidth + key.mGap;
- Integer count = histogram.get(width);
- if (count == null)
- count = 0;
- histogram.put(width, ++count);
- if (count > maxCount) {
- maxCount = count;
- mostCommonWidth = width;
- }
- }
- mKeyDetector.setProximityThreshold(mostCommonWidth);
- }
-
- @Override
- public void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- // Release the buffer, if any and it will be reallocated on the next draw
- mBuffer = null;
- }
-
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -641,19 +610,18 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
canvas.drawBitmap(mBuffer, 0, 0, null);
}
- @SuppressWarnings("unused")
private void onBufferDraw() {
+ final int width = getWidth();
+ final int height = getHeight();
+ if (width == 0 || height == 0)
+ return;
if (mBuffer == null || mKeyboardChanged) {
- if (mBuffer == null || mKeyboardChanged &&
- (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) {
- // Make sure our bitmap is at least 1x1
- final int width = Math.max(1, getWidth());
- final int height = Math.max(1, getHeight());
- mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- mCanvas = new Canvas(mBuffer);
- }
- invalidateAllKeys();
mKeyboardChanged = false;
+ mDirtyRect.union(0, 0, width, height);
+ }
+ if (mBuffer == null || mBuffer.getWidth() != width || mBuffer.getHeight() != height) {
+ mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBuffer);
}
final Canvas canvas = mCanvas;
canvas.clipRect(mDirtyRect, Op.REPLACE);
@@ -662,30 +630,19 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
final Paint paint = mPaint;
final Drawable keyBackground = mKeyBackground;
- final Rect clipRegion = mClipRegion;
final Rect padding = mPadding;
final int kbdPaddingLeft = getPaddingLeft();
final int kbdPaddingTop = getPaddingTop();
final Key[] keys = mKeys;
- final Key invalidKey = mInvalidatedKey;
final boolean isManualTemporaryUpperCase = mKeyboard.isManualTemporaryUpperCase();
+ final boolean drawSingleKey = (mInvalidatedKey != null
+ && mInvalidatedKeyRect.contains(mDirtyRect));
- boolean drawSingleKey = false;
- if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
- // TODO we should use Rect.inset and Rect.contains here.
- // Is clipRegion completely contained within the invalidated key?
- if (invalidKey.mX + kbdPaddingLeft - 1 <= clipRegion.left &&
- invalidKey.mY + kbdPaddingTop - 1 <= clipRegion.top &&
- invalidKey.mX + invalidKey.mWidth + kbdPaddingLeft + 1 >= clipRegion.right &&
- invalidKey.mY + invalidKey.mHeight + kbdPaddingTop + 1 >= clipRegion.bottom) {
- drawSingleKey = true;
- }
- }
canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
final int keyCount = keys.length;
for (int i = 0; i < keyCount; i++) {
final Key key = keys[i];
- if (drawSingleKey && invalidKey != key) {
+ if (drawSingleKey && key != mInvalidatedKey) {
continue;
}
int[] drawableState = key.getCurrentDrawableState();
@@ -739,16 +696,23 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
} else {
positionX = (key.mWidth + padding.left - padding.right) / 2;
paint.setTextAlign(Align.CENTER);
- if (DEBUG_SHOW_ALIGN && label.length() > 1)
- drawVerticalLine(canvas, positionX, rowHeight, 0xc0008080, new Paint());
+ if (DEBUG_SHOW_ALIGN) {
+ if (label.length() > 1)
+ drawVerticalLine(canvas, positionX, rowHeight, 0xc0008080, new Paint());
+ }
}
if (key.mManualTemporaryUpperCaseHintIcon != null && isManualTemporaryUpperCase) {
paint.setColor(mKeyTextColorDisabled);
} else {
paint.setColor(mKeyTextColor);
}
- // Set a drop shadow for the text
- paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
+ if (key.mEnabled) {
+ // Set a drop shadow for the text
+ paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
+ } else {
+ // Make label invisible
+ paint.setColor(Color.TRANSPARENT);
+ }
canvas.drawText(label, positionX, baseline, paint);
// Turn off drop shadow
paint.setShadowLayer(0, 0, 0, 0);
@@ -811,32 +775,13 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
canvas.drawLine(0, i * ch, cw * mKeyboard.GRID_WIDTH, i * ch, p);
}
- mInvalidatedKey = null;
// Overlay a dark rectangle to dim the keyboard
if (mMiniKeyboardView != null) {
paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24);
- canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
- }
-
- if (DEBUG) {
- if (mShowTouchPoints) {
- for (PointerTracker tracker : mPointerTrackers) {
- int startX = tracker.getStartX();
- int startY = tracker.getStartY();
- int lastX = tracker.getLastX();
- int lastY = tracker.getLastY();
- paint.setAlpha(128);
- paint.setColor(0xFFFF0000);
- canvas.drawCircle(startX, startY, 3, paint);
- canvas.drawLine(startX, startY, lastX, lastY, paint);
- paint.setColor(0xFF0000FF);
- canvas.drawCircle(lastX, lastY, 3, paint);
- paint.setColor(0xFF00FF00);
- canvas.drawCircle((startX + lastX) / 2, (startY + lastY) / 2, 2, paint);
- }
- }
+ canvas.drawRect(0, 0, width, height, paint);
}
+ mInvalidatedKey = null;
mDrawPending = false;
mDirtyRect.setEmpty();
}
@@ -1050,12 +995,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
if (key == null)
return;
mInvalidatedKey = key;
- // TODO we should clean up this and record key's region to use in onBufferDraw.
- mDirtyRect.union(key.mX + getPaddingLeft(), key.mY + getPaddingTop(),
- key.mX + key.mWidth + getPaddingLeft(), key.mY + key.mHeight + getPaddingTop());
+ mInvalidatedKeyRect.set(0, 0, key.mWidth, key.mHeight);
+ mInvalidatedKeyRect.offset(key.mX + getPaddingLeft(), key.mY + getPaddingTop());
+ mDirtyRect.union(mInvalidatedKeyRect);
onBufferDraw();
- invalidate(key.mX + getPaddingLeft(), key.mY + getPaddingTop(),
- key.mX + key.mWidth + getPaddingLeft(), key.mY + key.mHeight + getPaddingTop());
+ invalidate(mInvalidatedKeyRect);
}
private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index ffb8d6410..5820049bb 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -21,6 +21,7 @@ import com.android.inputmethod.latin.SubtypeSwitcher;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -31,17 +32,12 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.util.Log;
import java.util.List;
import java.util.Locale;
// TODO: We should remove this class
public class LatinKeyboard extends Keyboard {
-
- private static final boolean DEBUG_PREFERRED_LETTER = false;
- private static final String TAG = "LatinKeyboard";
-
public static final int OPACITY_FULLY_OPAQUE = 255;
private static final int SPACE_LED_LENGTH_PERCENT = 80;
@@ -69,15 +65,7 @@ public class LatinKeyboard extends Keyboard {
private final Drawable mEnabledShortcutIcon;
private final Drawable mDisabledShortcutIcon;
- private int[] mPrefLetterFrequencies;
- private int mPrefLetter;
- private int mPrefLetterX;
- private int mPrefLetterY;
- private int mPrefDistance;
-
private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
- private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f;
- private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f;
// Minimum width of space key preview (proportional to keyboard width)
private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f;
// Height in space key the language name will be drawn. (proportional to space key height)
@@ -167,6 +155,8 @@ public class LatinKeyboard extends Keyboard {
}
private void updateSpacebarForLocale(boolean isAutoCorrection) {
+ if (mSpaceKey == null)
+ return;
final Resources res = mContext.getResources();
// If application locales are explicitly selected.
if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
@@ -265,7 +255,7 @@ public class LatinKeyboard extends Keyboard {
final boolean allowVariableTextSize = true;
final String language = layoutSpacebar(paint, subtypeSwitcher.getInputLocale(),
mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
- getTextSizeFromTheme(textStyle, defaultTextSize),
+ getTextSizeFromTheme(mContext.getTheme(), textStyle, defaultTextSize),
allowVariableTextSize);
// Draw language text with shadow
@@ -334,18 +324,9 @@ public class LatinKeyboard extends Keyboard {
return mSpaceDragLastDiff > 0 ? 1 : -1;
}
- public void setPreferredLetters(int[] frequencies) {
- mPrefLetterFrequencies = frequencies;
- mPrefLetter = 0;
- }
-
public void keyReleased() {
mCurrentlyInSpace = false;
mSpaceDragLastDiff = 0;
- mPrefLetter = 0;
- mPrefLetterX = 0;
- mPrefLetterY = 0;
- mPrefDistance = Integer.MAX_VALUE;
if (mSpaceKey != null) {
updateLocaleDrag(Integer.MAX_VALUE);
}
@@ -381,80 +362,6 @@ public class LatinKeyboard extends Keyboard {
return isOnSpace;
}
}
- } else if (mPrefLetterFrequencies != null) {
- // New coordinate? Reset
- if (mPrefLetterX != x || mPrefLetterY != y) {
- mPrefLetter = 0;
- mPrefDistance = Integer.MAX_VALUE;
- }
- // Handle preferred next letter
- final int[] pref = mPrefLetterFrequencies;
- if (mPrefLetter > 0) {
- if (DEBUG_PREFERRED_LETTER) {
- if (mPrefLetter == code && !key.isOnKey(x, y)) {
- Log.d(TAG, "CORRECTED !!!!!!");
- }
- }
- return mPrefLetter == code;
- } else {
- final boolean isOnKey = key.isOnKey(x, y);
- int[] nearby = getNearestKeys(x, y);
- List<Key> nearbyKeys = getKeys();
- if (isOnKey) {
- // If it's a preferred letter
- if (inPrefList(code, pref)) {
- // Check if its frequency is much lower than a nearby key
- mPrefLetter = code;
- mPrefLetterX = x;
- mPrefLetterY = y;
- for (int i = 0; i < nearby.length; i++) {
- Key k = nearbyKeys.get(nearby[i]);
- if (k != key && inPrefList(k.mCode, pref)) {
- final int dist = distanceFrom(k, x, y);
- if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_LOW_PROB) &&
- (pref[k.mCode] > pref[mPrefLetter] * 3)) {
- mPrefLetter = k.mCode;
- mPrefDistance = dist;
- if (DEBUG_PREFERRED_LETTER) {
- Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!");
- }
- break;
- }
- }
- }
-
- return mPrefLetter == code;
- }
- }
-
- // Get the surrounding keys and intersect with the preferred list
- // For all in the intersection
- // if distance from touch point is within a reasonable distance
- // make this the pref letter
- // If no pref letter
- // return inside;
- // else return thiskey == prefletter;
-
- for (int i = 0; i < nearby.length; i++) {
- Key k = nearbyKeys.get(nearby[i]);
- if (inPrefList(k.mCode, pref)) {
- final int dist = distanceFrom(k, x, y);
- if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_HIGH_PROB)
- && dist < mPrefDistance) {
- mPrefLetter = k.mCode;
- mPrefLetterX = x;
- mPrefLetterY = y;
- mPrefDistance = dist;
- }
- }
- }
- // Didn't find any
- if (mPrefLetter == 0) {
- return isOnKey;
- } else {
- return mPrefLetter == code;
- }
- }
}
// Lock into the spacebar
@@ -463,19 +370,6 @@ public class LatinKeyboard extends Keyboard {
return key.isOnKey(x, y);
}
- private boolean inPrefList(int code, int[] pref) {
- if (code < pref.length && code >= 0) return pref[code] > 0;
- return false;
- }
-
- private int distanceFrom(Key k, int x, int y) {
- if (y > k.mY && y < k.mY + k.mHeight) {
- return Math.abs(k.mX + k.mWidth / 2 - x);
- } else {
- return Integer.MAX_VALUE;
- }
- }
-
@Override
public int[] getNearestKeys(int x, int y) {
if (mCurrentlyInSpace) {
@@ -487,8 +381,8 @@ public class LatinKeyboard extends Keyboard {
}
}
- private int getTextSizeFromTheme(int style, int defValue) {
- TypedArray array = mContext.getTheme().obtainStyledAttributes(
+ private static int getTextSizeFromTheme(Theme theme, int style, int defValue) {
+ TypedArray array = theme.obtainStyledAttributes(
style, new int[] { android.R.attr.textSize });
int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
return textSize;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index af2fd5ce1..6c3ad5edb 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -66,7 +66,8 @@ public class LatinKeyboardView extends KeyboardView {
}
}
- public void setLatinKeyboard(LatinKeyboard newKeyboard) {
+ @Override
+ public void setKeyboard(Keyboard newKeyboard) {
final LatinKeyboard oldKeyboard = getLatinKeyboard();
if (oldKeyboard != null) {
// Reset old keyboard state before switching to new keyboard.
@@ -80,7 +81,7 @@ public class LatinKeyboardView extends KeyboardView {
mLastRowY = (newKeyboard.getHeight() * 3) / 4;
}
- public LatinKeyboard getLatinKeyboard() {
+ private LatinKeyboard getLatinKeyboard() {
Keyboard keyboard = getKeyboard();
if (keyboard instanceof LatinKeyboard) {
return (LatinKeyboard)keyboard;
@@ -141,6 +142,9 @@ public class LatinKeyboardView extends KeyboardView {
* KeyboardView.
*/
private boolean handleSuddenJump(MotionEvent me) {
+ // If device has distinct multi touch panel, there is no need to check sudden jump.
+ if (hasDistinctMultitouch())
+ return false;
final int action = me.getAction();
final int x = (int) me.getX();
final int y = (int) me.getY();
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
index f04991eb7..a8750d378 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
@@ -35,24 +35,24 @@ public class MiniKeyboardKeyDetector extends KeyDetector {
}
@Override
- public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+ public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
final Key[] keys = getKeys();
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
- int closestKeyIndex = NOT_A_KEY;
- int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
+ int nearestIndex = NOT_A_KEY;
+ int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
final int keyCount = keys.length;
for (int index = 0; index < keyCount; index++) {
final int dist = keys[index].squaredDistanceToEdge(touchX, touchY);
- if (dist < closestKeyDist) {
- closestKeyIndex = index;
- closestKeyDist = dist;
+ if (dist < nearestDist) {
+ nearestIndex = index;
+ nearestDist = dist;
}
}
- if (allKeys != null && closestKeyIndex != NOT_A_KEY)
- allKeys[0] = keys[closestKeyIndex].mCode;
- return closestKeyIndex;
+ if (allCodes != null && nearestIndex != NOT_A_KEY)
+ allCodes[0] = keys[nearestIndex].mCode;
+ return nearestIndex;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index a981f724f..ac375473a 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -129,32 +129,42 @@ public class PointerTracker {
}
// Returns true if keyboard has been changed by this callback.
- private boolean callListenerOnPressAndCheckKeyboardLayoutChange(int primaryCode) {
+ private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) {
if (DEBUG_LISTENER)
- Log.d(TAG, "onPress : " + keyCodePrintable(primaryCode));
- mListener.onPress(primaryCode);
- final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
- mKeyboardLayoutHasBeenChanged = false;
- return keyboardLayoutHasBeenChanged;
+ Log.d(TAG, "onPress : " + keyCodePrintable(key.mCode));
+ if (key.mEnabled) {
+ mListener.onPress(key.mCode);
+ final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
+ mKeyboardLayoutHasBeenChanged = false;
+ return keyboardLayoutHasBeenChanged;
+ }
+ return false;
}
- private void callListenerOnCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
+ // Note that we need primaryCode argument because the keyboard may in shifted state and the
+ // primaryCode is different from {@link Key#mCode}.
+ private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) {
if (DEBUG_LISTENER)
Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode)
+ " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y);
- mListener.onCodeInput(primaryCode, keyCodes, x, y);
+ if (key.mEnabled)
+ mListener.onCodeInput(primaryCode, keyCodes, x, y);
}
- private void callListenerOnTextInput(CharSequence text) {
+ private void callListenerOnTextInput(Key key) {
if (DEBUG_LISTENER)
- Log.d(TAG, "onTextInput: text=" + text);
- mListener.onTextInput(text);
+ Log.d(TAG, "onTextInput: text=" + key.mOutputText);
+ if (key.mEnabled)
+ mListener.onTextInput(key.mOutputText);
}
- private void callListenerOnRelease(int primaryCode) {
+ // Note that we need primaryCode argument because the keyboard may in shifted state and the
+ // primaryCode is different from {@link Key#mCode}.
+ private void callListenerOnRelease(Key key, int primaryCode) {
if (DEBUG_LISTENER)
Log.d(TAG, "onRelease : " + keyCodePrintable(primaryCode));
- mListener.onRelease(primaryCode);
+ if (key.mEnabled)
+ mListener.onRelease(primaryCode);
}
private void callListenerOnCancelInput() {
@@ -313,7 +323,7 @@ public class PointerTracker {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update keyIndex according to the new
// keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(mKeys[keyIndex].mCode))
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(mKeys[keyIndex]))
keyIndex = mKeyState.onDownKey(x, y, eventTime);
}
if (isValidKeyIndex(keyIndex)) {
@@ -346,7 +356,7 @@ public class PointerTracker {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update keyIndex according to the
// new keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode))
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex)))
keyIndex = keyState.onMoveKey(x, y);
keyState.onMoveToNewKey(keyIndex, x, y);
startLongPressTimer(keyIndex);
@@ -355,13 +365,13 @@ public class PointerTracker {
// onRelease() first to notify that the previous key has been released, then call
// onPress() to notify that the new key is being pressed.
mIsInSlidingKeyInput = true;
- callListenerOnRelease(oldKey.mCode);
+ callListenerOnRelease(oldKey, oldKey.mCode);
mHandler.cancelLongPressTimers();
if (mIsAllowedSlidingKeyInput) {
// This onPress call may have changed keyboard layout. Those cases are detected
// at {@link #setKeyboard}. In those cases, we should update keyIndex according
// to the new keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode))
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex)))
keyIndex = keyState.onMoveKey(x, y);
keyState.onMoveToNewKey(keyIndex, x, y);
startLongPressTimer(keyIndex);
@@ -390,7 +400,7 @@ public class PointerTracker {
// The pointer has been slid out from the previous key, we must call onRelease() to
// notify that the previous key has been released.
mIsInSlidingKeyInput = true;
- callListenerOnRelease(oldKey.mCode);
+ callListenerOnRelease(oldKey, oldKey.mCode);
mHandler.cancelLongPressTimers();
if (mIsAllowedSlidingKeyInput) {
keyState.onMoveToNewKey(keyIndex, x ,y);
@@ -490,15 +500,6 @@ public class PointerTracker {
return mKeyState.getDownTime();
}
- // These package scope methods are only for debugging purpose.
- /* package */ int getStartX() {
- return mKeyState.getStartX();
- }
-
- /* package */ int getStartY() {
- return mKeyState.getStartY();
- }
-
private boolean isMinorMoveBounce(int x, int y, int newKey) {
if (mKeys == null || mKeyHysteresisDistanceSquared < 0)
throw new IllegalStateException("keyboard and/or hysteresis not set");
@@ -548,8 +549,8 @@ public class PointerTracker {
return;
}
if (key.mOutputText != null) {
- callListenerOnTextInput(key.mOutputText);
- callListenerOnRelease(key.mCode);
+ callListenerOnTextInput(key);
+ callListenerOnRelease(key, key.mCode);
} else {
int code = key.mCode;
final int[] codes = mKeyDetector.newCodeArray();
@@ -570,9 +571,8 @@ public class PointerTracker {
codes[1] = codes[0];
codes[0] = code;
}
- if (key.mEnabled)
- callListenerOnCodeInput(code, codes, x, y);
- callListenerOnRelease(code);
+ callListenerOnCodeInput(key, code, codes, x, y);
+ callListenerOnRelease(key, code);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java b/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java
index 250bb95eb..a62ed96a3 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTrackerKeyState.java
@@ -23,8 +23,6 @@ package com.android.inputmethod.keyboard;
private final KeyDetector mKeyDetector;
// The position and time at which first down event occurred.
- private int mStartX;
- private int mStartY;
private long mDownTime;
private long mUpTime;
@@ -54,14 +52,6 @@ package com.android.inputmethod.keyboard;
return mKeyY;
}
- public int getStartX() {
- return mStartX;
- }
-
- public int getStartY() {
- return mStartY;
- }
-
public long getDownTime() {
return mDownTime;
}
@@ -79,8 +69,6 @@ package com.android.inputmethod.keyboard;
}
public int onDownKey(int x, int y, long eventTime) {
- mStartX = x;
- mStartY = y;
mDownTime = eventTime;
return onMoveToNewKey(onMoveKeyInternal(x, y), x, y);
}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
index 0920da2cb..c3fd1984b 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
@@ -16,49 +16,106 @@
package com.android.inputmethod.keyboard;
+import android.util.Log;
+
import java.util.Arrays;
public class ProximityKeyDetector extends KeyDetector {
+ private static final String TAG = ProximityKeyDetector.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
private static final int MAX_NEARBY_KEYS = 12;
// working area
- private int[] mDistances = new int[MAX_NEARBY_KEYS];
+ private final int[] mDistances = new int[MAX_NEARBY_KEYS];
+ private final int[] mIndices = new int[MAX_NEARBY_KEYS];
@Override
protected int getMaxNearbyKeys() {
return MAX_NEARBY_KEYS;
}
+ private void initializeNearbyKeys() {
+ Arrays.fill(mDistances, Integer.MAX_VALUE);
+ Arrays.fill(mIndices, NOT_A_KEY);
+ }
+
+ /**
+ * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
+ *
+ * @param keyIndex index of the key.
+ * @param distance distance between the key's edge and user touched point.
+ * @return order of the key in the nearby buffer, 0 if it is the nearest key.
+ */
+ private int sortNearbyKeys(int keyIndex, int distance) {
+ final int[] distances = mDistances;
+ final int[] indices = mIndices;
+ for (int insertPos = 0; insertPos < distances.length; insertPos++) {
+ if (distance < distances[insertPos]) {
+ final int nextPos = insertPos + 1;
+ if (nextPos < distances.length) {
+ System.arraycopy(distances, insertPos, distances, nextPos,
+ distances.length - nextPos);
+ System.arraycopy(indices, insertPos, indices, nextPos,
+ indices.length - nextPos);
+ }
+ distances[insertPos] = distance;
+ indices[insertPos] = keyIndex;
+ return insertPos;
+ }
+ }
+ return distances.length;
+ }
+
+ private void getNearbyKeyCodes(final int[] allCodes) {
+ final Key[] keys = getKeys();
+ final int[] indices = mIndices;
+
+ // allCodes[0] should always have the key code even if it is a non-letter key.
+ if (indices[0] == NOT_A_KEY) {
+ allCodes[0] = NOT_A_CODE;
+ return;
+ }
+
+ int numCodes = 0;
+ for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) {
+ final int index = indices[j];
+ if (index == NOT_A_KEY)
+ break;
+ final int code = keys[index].mCode;
+ // filter out a non-letter key from nearby keys
+ if (code < Keyboard.CODE_SPACE)
+ continue;
+ allCodes[numCodes++] = code;
+ }
+ }
+
@Override
- public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+ public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
final Key[] keys = getKeys();
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
+ initializeNearbyKeys();
int primaryIndex = NOT_A_KEY;
- final int[] distances = mDistances;
- Arrays.fill(distances, Integer.MAX_VALUE);
for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
final Key key = keys[index];
final boolean isInside = key.isInside(touchX, touchY);
- if (isInside)
- primaryIndex = index;
- final int dist = key.squaredDistanceToEdge(touchX, touchY);
- if (isInside || (mProximityCorrectOn && dist < mProximityThresholdSquare)) {
- if (allKeys == null) continue;
- // Find insertion point
- for (int j = 0; j < distances.length; j++) {
- if (distances[j] > dist) {
- final int nextPos = j + 1;
- System.arraycopy(distances, j, distances, nextPos,
- distances.length - nextPos);
- System.arraycopy(allKeys, j, allKeys, nextPos,
- allKeys.length - nextPos);
- distances[j] = dist;
- allKeys[j] = key.mCode;
- break;
- }
- }
+ final int distance = key.squaredDistanceToEdge(touchX, touchY);
+ if (isInside || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
+ final int insertedPosition = sortNearbyKeys(index, distance);
+ if (insertedPosition == 0 && isInside)
+ primaryIndex = index;
+ }
+ }
+
+ if (allCodes != null && allCodes.length > 0) {
+ getNearbyKeyCodes(allCodes);
+ if (DEBUG) {
+ Log.d(TAG, "x=" + x + " y=" + y
+ + " primary="
+ + (primaryIndex == NOT_A_KEY ? "none" : keys[primaryIndex].mCode)
+ + " codes=" + Arrays.toString(allCodes));
}
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 813f7d32f..ff7e2b88a 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.util.Log;
+import java.io.File;
import java.util.Arrays;
/**
@@ -72,9 +73,40 @@ public class BinaryDictionary extends Dictionary {
public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
synchronized (sInstance) {
sInstance.closeInternal();
- if (resId != 0) {
- sInstance.loadDictionary(context, resId);
+ try {
+ final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
+ if (afd == null) {
+ Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
+ return null;
+ }
+ final String sourceDir = context.getApplicationInfo().sourceDir;
+ final File packagePath = new File(sourceDir);
+ // TODO: Come up with a way to handle a directory.
+ if (!packagePath.isFile()) {
+ Log.e(TAG, "sourceDir is not a file: " + sourceDir);
+ return null;
+ }
+ sInstance.loadDictionary(sourceDir, afd.getStartOffset(), afd.getLength());
sInstance.mDicTypeId = dicTypeId;
+ } catch (android.content.res.Resources.NotFoundException e) {
+ Log.e(TAG, "Could not find the resource. resId=" + resId);
+ return null;
+ }
+ }
+ return sInstance;
+ }
+
+ // For unit test
+ /* package */ static BinaryDictionary initDictionary(File dictionary, long startOffset,
+ long length, int dicTypeId) {
+ synchronized (sInstance) {
+ sInstance.closeInternal();
+ if (dictionary.isFile()) {
+ sInstance.loadDictionary(dictionary.getAbsolutePath(), startOffset, length);
+ sInstance.mDicTypeId = dicTypeId;
+ } else {
+ Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath());
+ return null;
}
}
return sInstance;
@@ -86,33 +118,21 @@ public class BinaryDictionary extends Dictionary {
private native void closeNative(int dict);
private native boolean isValidWordNative(int nativeData, char[] word, int wordLength);
private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize,
- char[] outputChars, int[] frequencies,
- int[] nextLettersFrequencies, int nextLettersSize);
+ char[] outputChars, int[] frequencies);
private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength,
int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies,
int maxWordLength, int maxBigrams, int maxAlternatives);
- private final void loadDictionary(Context context, int resId) {
- try {
- final AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
- if (afd == null) {
- Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
- return;
- }
- mNativeDict = openNative(context.getApplicationInfo().sourceDir,
- afd.getStartOffset(), afd.getLength(),
+ private final void loadDictionary(String path, long startOffset, long length) {
+ mNativeDict = openNative(path, startOffset, length,
TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
- mDictLength = afd.getLength();
- } catch (android.content.res.Resources.NotFoundException e) {
- Log.e(TAG, "Could not find the resource. resId=" + resId);
- return;
- }
+ mDictLength = length;
}
@Override
public void getBigrams(final WordComposer codes, final CharSequence previousWord,
- final WordCallback callback, int[] nextLettersFrequencies) {
+ final WordCallback callback) {
if (mNativeDict == 0) return;
char[] chars = previousWord.toString().toCharArray();
@@ -144,15 +164,14 @@ public class BinaryDictionary extends Dictionary {
}
@Override
- public void getWords(final WordComposer codes, final WordCallback callback,
- int[] nextLettersFrequencies) {
+ public void getWords(final WordComposer codes, final WordCallback callback) {
if (mNativeDict == 0) return;
final int codesSize = codes.size();
// Won't deal with really long words.
if (codesSize > MAX_WORD_LENGTH - 1) return;
- Arrays.fill(mInputCodes, -1);
+ Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE);
for (int i = 0; i < codesSize; i++) {
int[] alternatives = codes.getCodesAt(i);
System.arraycopy(alternatives, 0, mInputCodes, i * MAX_ALTERNATIVES,
@@ -162,8 +181,7 @@ public class BinaryDictionary extends Dictionary {
Arrays.fill(mFrequencies, 0);
int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, mOutputChars,
- mFrequencies, nextLettersFrequencies,
- nextLettersFrequencies != null ? nextLettersFrequencies.length : 0);
+ mFrequencies);
for (int j = 0; j < count; ++j) {
if (mFrequencies[j] < 1) break;
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index fc45c7c75..9699ad136 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -54,7 +54,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
private static final int MAX_SUGGESTIONS = 16;
- private static boolean DBG = LatinImeLogger.sDBG;
+ private static final boolean DBG = LatinImeLogger.sDBG;
private final ArrayList<View> mWords = new ArrayList<View>();
private final boolean mConfigCandidateHighlightFontColorEnabled;
@@ -226,10 +226,14 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
}
final String debugString = info.getDebugString();
if (DBG) {
- if (!TextUtils.isEmpty(debugString)) {
+ if (TextUtils.isEmpty(debugString)) {
+ dv.setVisibility(GONE);
+ } else {
dv.setText(debugString);
dv.setVisibility(VISIBLE);
}
+ } else {
+ dv.setVisibility(GONE);
}
} else {
dv.setVisibility(GONE);
@@ -249,8 +253,10 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word);
final Spannable word = new SpannableString(autoCorrectedWord);
final int wordLength = word.length();
- word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
- word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ word.setSpan(mInvertedForegroundColorSpan, 0, wordLength,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
tv.setText(word);
mShowingAutoCorrectionInverted = true;
}
diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java
index 03211f36b..2f1e7c2b8 100644
--- a/java/src/com/android/inputmethod/latin/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/DebugSettings.java
@@ -20,6 +20,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
+import android.os.Process;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceActivity;
import android.util.Log;
@@ -30,6 +31,7 @@ public class DebugSettings extends PreferenceActivity
private static final String TAG = "DebugSettings";
private static final String DEBUG_MODE_KEY = "debug_mode";
+ private boolean mServiceNeedsRestart = false;
private CheckBoxPreference mDebugMode;
@Override
@@ -39,16 +41,24 @@ public class DebugSettings extends PreferenceActivity
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
prefs.registerOnSharedPreferenceChangeListener(this);
+ mServiceNeedsRestart = false;
mDebugMode = (CheckBoxPreference) findPreference(DEBUG_MODE_KEY);
updateDebugMode();
}
@Override
+ protected void onStop() {
+ super.onStop();
+ if (mServiceNeedsRestart) Process.killProcess(Process.myPid());
+ }
+
+ @Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals(DEBUG_MODE_KEY)) {
if (mDebugMode != null) {
mDebugMode.setChecked(prefs.getBoolean(DEBUG_MODE_KEY, false));
updateDebugMode();
+ mServiceNeedsRestart = true;
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 74933595c..56f0cc503 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -61,14 +61,9 @@ public abstract class Dictionary {
* words are added through the callback object.
* @param composer the key sequence to match
* @param callback the callback object to send matched words to as possible candidates
- * @param nextLettersFrequencies array of frequencies of next letters that could follow the
- * word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
- * a non-zero value on returning from this method.
- * Pass in null if you don't want the dictionary to look up next letters.
* @see WordCallback#addWord(char[], int, int)
*/
- abstract public void getWords(final WordComposer composer, final WordCallback callback,
- int[] nextLettersFrequencies);
+ abstract public void getWords(final WordComposer composer, final WordCallback callback);
/**
* Searches for pairs in the bigram dictionary that matches the previous word and all the
@@ -76,13 +71,9 @@ public abstract class Dictionary {
* @param composer the key sequence to match
* @param previousWord the word before
* @param callback the callback object to send possible word following previous word
- * @param nextLettersFrequencies array of frequencies of next letters that could follow the
- * word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
- * a non-zero value on returning from this method.
- * Pass in null if you don't want the dictionary to look up next letters.
*/
public void getBigrams(final WordComposer composer, final CharSequence previousWord,
- final WordCallback callback, int[] nextLettersFrequencies) {
+ final WordCallback callback) {
// empty base implementation
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 0fc86c335..b10e7a61e 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -37,7 +37,6 @@ public class ExpandableDictionary extends Dictionary {
private int mDicTypeId;
private int mMaxDepth;
private int mInputLength;
- private int[] mNextLettersFrequencies;
private StringBuilder sb = new StringBuilder(MAX_WORD_LENGTH);
private static final char QUOTE = '\'';
@@ -191,8 +190,7 @@ public class ExpandableDictionary extends Dictionary {
}
@Override
- public void getWords(final WordComposer codes, final WordCallback callback,
- int[] nextLettersFrequencies) {
+ public void getWords(final WordComposer codes, final WordCallback callback) {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) startDictionaryLoadingTaskLocked();
@@ -201,7 +199,6 @@ public class ExpandableDictionary extends Dictionary {
}
mInputLength = codes.size();
- mNextLettersFrequencies = nextLettersFrequencies;
if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
// Cache the codes so that we don't have to lookup an array list
for (int i = 0; i < mInputLength; i++) {
@@ -282,11 +279,6 @@ public class ExpandableDictionary extends Dictionary {
DataType.UNIGRAM)) {
return;
}
- // Add to frequency of next letters for predictive correction
- if (mNextLettersFrequencies != null && depth >= inputIndex && skipPos < 0
- && mNextLettersFrequencies.length > word[inputIndex]) {
- mNextLettersFrequencies[word[inputIndex]]++;
- }
}
if (children != null) {
getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex,
@@ -427,7 +419,7 @@ public class ExpandableDictionary extends Dictionary {
@Override
public void getBigrams(final WordComposer codes, final CharSequence previousWord,
- final WordCallback callback, int[] nextLettersFrequencies) {
+ final WordCallback callback) {
if (!reloadDictionaryIfRequired()) {
runReverseLookUp(previousWord, callback);
}
@@ -516,7 +508,7 @@ public class ExpandableDictionary extends Dictionary {
}
}
- static char toLowerCase(char c) {
+ private static char toLowerCase(char c) {
char baseChar = c;
if (c < BASE_CHARS.length) {
baseChar = BASE_CHARS[c];
@@ -535,7 +527,7 @@ public class ExpandableDictionary extends Dictionary {
* if c is not a combined character, or the base character if it
* is combined.
*/
- static final char BASE_CHARS[] = {
+ private static final char BASE_CHARS[] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5ce1b7e95..c9e7f8b39 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -81,8 +81,7 @@ import java.util.Locale;
/**
* Input method implementation for Qwerty'ish keyboard.
*/
-public class LatinIME extends InputMethodService implements KeyboardActionListener,
- SharedPreferences.OnSharedPreferenceChangeListener {
+public class LatinIME extends InputMethodService implements KeyboardActionListener {
private static final String TAG = "LatinIME";
private static final boolean PERF_DEBUG = false;
private static final boolean TRACE = false;
@@ -186,7 +185,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Keeps track of most recently inserted text (multi-character key) for reverting
private CharSequence mEnteredText;
- private boolean mRefreshKeyboardRequired;
private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
@@ -323,7 +321,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
if (inputView != null) {
- final LatinKeyboard keyboard = inputView.getLatinKeyboard();
+ final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
// The language is never displayed when the delay is zero.
if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
@@ -359,9 +357,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// but always use the default setting defined in the resources.
if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
- res.getBoolean(R.bool.default_recorrection_enabled));
+ res.getBoolean(R.bool.config_default_recorrection_enabled));
} else {
- mReCorrectionEnabled = res.getBoolean(R.bool.default_recorrection_enabled);
+ mReCorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled);
}
mConfigEnableShowSubtypeSettings = res.getBoolean(
@@ -395,7 +393,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(mReceiver, filter);
mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
- prefs.registerOnSharedPreferenceChangeListener(this);
}
/**
@@ -497,12 +494,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return container;
}
- private static boolean isPasswordVariation(int variation) {
- return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
- || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
- || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
- }
-
private static boolean isEmailVariation(int variation) {
return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|| variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
@@ -523,20 +514,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSubtypeSwitcher.updateParametersOnStartInputView();
- if (mRefreshKeyboardRequired) {
- mRefreshKeyboardRequired = false;
- onRefreshKeyboard();
- }
-
TextEntryState.newSession(this);
// Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
// know now whether this is a password text field, because we need to know now whether we
// want to enable the voice button.
- mVoiceConnector.resetVoiceStates(isPasswordVariation(
- attribute.inputType & InputType.TYPE_MASK_VARIATION));
+ mVoiceConnector.resetVoiceStates(Utils.isPasswordInputType(attribute.inputType)
+ || Utils.isVisiblePasswordInputType(attribute.inputType));
- final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
+ final int mode = initializeInputAttributesAndGetMode(attribute);
inputView.closing();
mEnteredText = null;
@@ -547,7 +533,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
loadSettings(attribute);
if (mSubtypeSwitcher.isKeyboardMode()) {
- switcher.loadKeyboard(mode, attribute.imeOptions,
+ switcher.loadKeyboard(mode, attribute,
mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary());
switcher.updateShiftState();
@@ -571,7 +557,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
}
- private int initializeInputAttributesAndGetMode(int inputType) {
+ // TODO: Separate calculating keyboard mode from initializing attributes, and make it an
+ // utility method in {@link Utils}.
+ private int initializeInputAttributesAndGetMode(EditorInfo attribute) {
+ if (attribute == null) return KeyboardId.MODE_TEXT;
+ final int inputType = attribute.inputType;
final int variation = inputType & InputType.TYPE_MASK_VARIATION;
mAutoSpace = false;
mInputTypeNoAutoCorrect = false;
@@ -591,16 +581,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
case InputType.TYPE_CLASS_TEXT:
mIsSettingsSuggestionStripOn = true;
// Make sure that passwords are not displayed in candidate view
- if (isPasswordVariation(variation)) {
+ if (Utils.isPasswordInputType(inputType)
+ || Utils.isVisiblePasswordInputType(inputType)) {
mIsSettingsSuggestionStripOn = false;
}
- if (isEmailVariation(variation)
+ if (LatinIME.isEmailVariation(variation)
|| variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
mAutoSpace = false;
} else {
mAutoSpace = true;
}
- if (isEmailVariation(variation)) {
+ if (LatinIME.isEmailVariation(variation)) {
mIsSettingsSuggestionStripOn = false;
mode = KeyboardId.MODE_EMAIL;
} else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
@@ -1467,26 +1458,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
public void switchToKeyboardView() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "Switch to keyboard view.");
- }
- View v = mKeyboardSwitcher.getInputView();
- if (v != null) {
- // Confirms that the keyboard view doesn't have parent view.
- ViewParent p = v.getParent();
- if (p != null && p instanceof ViewGroup) {
- ((ViewGroup) p).removeView(v);
- }
- setInputView(v);
- }
- setCandidatesViewShown(isCandidateStripVisible());
- updateInputViewShown();
- mHandler.postUpdateSuggestions();
+ if (DEBUG) {
+ Log.d(TAG, "Switch to keyboard view.");
+ }
+ View v = mKeyboardSwitcher.getInputView();
+ if (v != null) {
+ // Confirms that the keyboard view doesn't have parent view.
+ ViewParent p = v.getParent();
+ if (p != null && p instanceof ViewGroup) {
+ ((ViewGroup) p).removeView(v);
}
- });
+ setInputView(v);
+ }
+ setCandidatesViewShown(isCandidateStripVisible());
+ updateInputViewShown();
+ mHandler.postUpdateSuggestions();
}
public void clearSuggestions() {
@@ -1508,8 +1494,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
public void updateSuggestions() {
- mKeyboardSwitcher.setPreferredLetters(null);
-
// Check if we have a suggestion engine attached.
if ((mSuggest == null || !isSuggestionsRequested())
&& !mVoiceConnector.isVoiceInputHighlighted()) {
@@ -1528,7 +1512,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void showCorrections(WordAlternatives alternatives) {
- mKeyboardSwitcher.setPreferredLetters(null);
SuggestedWords.Builder builder = alternatives.getAlternatives();
builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
showSuggestions(builder.build(), alternatives.getOriginalWord());
@@ -1541,9 +1524,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
mKeyboardSwitcher.getInputView(), word, prevWord);
- int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
- mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
-
boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
&& mSuggest.hasAutoCorrection();
final CharSequence typedWord = word.getTypedWord();
@@ -1712,7 +1692,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
saveWordInHistory(suggestion);
mHasValidSuggestions = false;
mCommittedLength = suggestion.length();
- switcher.setPreferredLetters(null);
}
/**
@@ -1930,28 +1909,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSubtypeSwitcher.toggleLanguage(reset, next);
}
// Reload keyboard because the current language has been changed.
- KeyboardSwitcher switcher = mKeyboardSwitcher;
final EditorInfo attribute = getCurrentInputEditorInfo();
- final int mode = initializeInputAttributesAndGetMode((attribute != null)
- ? attribute.inputType : 0);
- final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
- switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
- mVoiceConnector.isVoiceButtonOnPrimary());
+ final int mode = initializeInputAttributesAndGetMode(attribute);
+ mKeyboardSwitcher.loadKeyboard(mode, attribute,
+ mVoiceConnector.isVoiceButtonEnabled(), mVoiceConnector.isVoiceButtonOnPrimary());
initSuggest();
- switcher.updateShiftState();
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
- mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
- if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
- mRefreshKeyboardRequired = true;
- } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) {
- mReCorrectionEnabled = sharedPreferences.getBoolean(
- Settings.PREF_RECORRECTION_ENABLED,
- mResources.getBoolean(R.bool.default_recorrection_enabled));
- }
+ mKeyboardSwitcher.updateShiftState();
}
@Override
@@ -2082,7 +2045,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void updateAutoTextEnabled() {
if (mSuggest == null) return;
- mSuggest.setAutoTextEnabled(mQuickFixes
+ mSuggest.setQuickFixesEnabled(mQuickFixes
&& SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
}
@@ -2121,7 +2084,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrateOn = vibrator != null && vibrator.hasVibrator()
&& prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
- mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, false);
+ mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
+ mResources.getBoolean(R.bool.config_default_sound_enabled));
mPopupOn = isPopupEnabled(prefs);
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
@@ -2272,10 +2236,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
di.dismiss();
switch (position) {
case 0:
- launchSettings();
+ mImm.showInputMethodPicker();
break;
case 1:
- mImm.showInputMethodPicker();
+ launchSettings();
break;
}
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 12338ce61..341d5add0 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -225,7 +225,9 @@ public class Settings extends PreferenceActivity
final String action;
if (android.os.Build.VERSION.SDK_INT
>= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 11) {
- action = "android.settings.INPUT_METHOD_AND_SUBTYPE_ENABLER";
+ // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS
+ // TODO: Can this be a constant instead of literal String constant?
+ action = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
} else {
action = "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION";
}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index f4262cc99..ee9dab3b7 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -371,12 +371,10 @@ public class SubtypeSwitcher {
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
mIsNetworkConnected = !noConnection;
- final LatinKeyboardView inputView = KeyboardSwitcher.getInstance().getInputView();
- if (inputView != null) {
- final LatinKeyboard keyboard = inputView.getLatinKeyboard();
- if (keyboard != null) {
- keyboard.updateShortcutKey(isShortcutAvailable(), inputView);
- }
+ final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
+ final LatinKeyboard keyboard = switcher.getLatinKeyboard();
+ if (keyboard != null) {
+ keyboard.updateShortcutKey(isShortcutAvailable(), switcher.getInputView());
}
}
@@ -426,8 +424,15 @@ public class SubtypeSwitcher {
if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getEnabledLanguages();
} else {
+ int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size();
+ // Workaround for explicitly specifying the voice language
+ if (enabledLanguageCount == 1) {
+ mEnabledLanguagesOfCurrentInputMethod.add(
+ mEnabledLanguagesOfCurrentInputMethod.get(0));
+ ++enabledLanguageCount;
+ }
return mEnabledLanguagesOfCurrentInputMethod.toArray(
- new String[mEnabledLanguagesOfCurrentInputMethod.size()]);
+ new String[enabledLanguageCount]);
}
}
@@ -465,14 +470,6 @@ public class SubtypeSwitcher {
}
}
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (mConfigUseSpacebarLanguageSwitcher) {
- if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
- mLanguageSwitcher.loadLocales(sharedPreferences);
- }
- }
- }
-
/**
* Change system locale for this application
* @param newLocale
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index ced355bb2..6466f7980 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -22,6 +22,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
@@ -64,7 +65,7 @@ public class Suggest implements Dictionary.WordCallback {
static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
- private static boolean DBG = LatinImeLogger.sDBG;
+ private static final boolean DBG = LatinImeLogger.sDBG;
private BinaryDictionary mMainDict;
@@ -80,18 +81,12 @@ public class Suggest implements Dictionary.WordCallback {
private static final int PREF_MAX_BIGRAMS = 60;
- private boolean mAutoTextEnabled;
+ private boolean mQuickFixesEnabled;
private double mAutoCorrectionThreshold;
private int[] mPriorities = new int[mPrefMaxSuggestions];
private int[] mBigramPriorities = new int[PREF_MAX_BIGRAMS];
- // Handle predictive correction for only the first 1280 characters for performance reasons
- // If we support scripts that need latin characters beyond that, we should probably use some
- // kind of a sparse array or language specific list with a mapping lookup table.
- // 1280 is the size of the BASE_CHARS array in ExpandableDictionary, which is a basic set of
- // latin characters.
- private int[] mNextLettersFrequencies = new int[1280];
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
@@ -109,6 +104,12 @@ public class Suggest implements Dictionary.WordCallback {
initPool();
}
+ // For unit test
+ /* package */ Suggest(File dictionary, long startOffset, long length) {
+ mMainDict = BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN);
+ initPool();
+ }
+
private void initPool() {
for (int i = 0; i < mPrefMaxSuggestions; i++) {
StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
@@ -116,8 +117,8 @@ public class Suggest implements Dictionary.WordCallback {
}
}
- public void setAutoTextEnabled(boolean enabled) {
- mAutoTextEnabled = enabled;
+ public void setQuickFixesEnabled(boolean enabled) {
+ mQuickFixesEnabled = enabled;
}
public int getCorrectionMode() {
@@ -209,7 +210,6 @@ public class Suggest implements Dictionary.WordCallback {
mIsAllUpperCase = wordComposer.isAllUpperCase();
collectGarbage(mSuggestions, mPrefMaxSuggestions);
Arrays.fill(mPriorities, 0);
- Arrays.fill(mNextLettersFrequencies, 0);
// Save a lowercase version of the original word
CharSequence typedWord = wordComposer.getTypedWord();
@@ -224,6 +224,7 @@ public class Suggest implements Dictionary.WordCallback {
mLowerOriginalWord = "";
}
+ double normalizedScore = Integer.MIN_VALUE;
if (wordComposer.size() == 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM
|| mCorrectionMode == CORRECTION_BASIC)) {
// At first character typed, search only the bigrams
@@ -236,16 +237,13 @@ public class Suggest implements Dictionary.WordCallback {
prevWordForBigram = lowerPrevWord;
}
if (mUserBigramDictionary != null) {
- mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this,
- mNextLettersFrequencies);
+ mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this);
}
if (mContactsDictionary != null) {
- mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this,
- mNextLettersFrequencies);
+ mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this);
}
if (mMainDict != null) {
- mMainDict.getBigrams(wordComposer, prevWordForBigram, this,
- mNextLettersFrequencies);
+ mMainDict.getBigrams(wordComposer, prevWordForBigram, this);
}
char currentChar = wordComposer.getTypedWord().charAt(0);
char currentCharUpper = Character.toUpperCase(currentChar);
@@ -270,10 +268,10 @@ public class Suggest implements Dictionary.WordCallback {
// At second character typed, search the unigrams (scores being affected by bigrams)
if (mUserDictionary != null || mContactsDictionary != null) {
if (mUserDictionary != null) {
- mUserDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
+ mUserDictionary.getWords(wordComposer, this);
}
if (mContactsDictionary != null) {
- mContactsDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
+ mContactsDictionary.getWords(wordComposer, this);
}
if (mSuggestions.size() > 0 && isValidWord(typedWord)
@@ -285,14 +283,14 @@ public class Suggest implements Dictionary.WordCallback {
mHasAutoCorrection = true;
}
}
- if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
+ if (mMainDict != null) mMainDict.getWords(wordComposer, this);
if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
&& mSuggestions.size() > 0 && mPriorities.length > 0) {
// TODO: when the normalized score of the first suggestion is nearly equals to
// the normalized score of the second suggestion, behave less aggressive.
- final double normalizedScore = Utils.calcNormalizedScore(
+ normalizedScore = Utils.calcNormalizedScore(
typedWord, mSuggestions.get(0), mPriorities[0]);
- if (LatinImeLogger.sDBG) {
+ if (DBG) {
Log.d(TAG, "Normalized " + typedWord + "," + mSuggestions.get(0) + ","
+ mPriorities[0] + ", " + normalizedScore
+ "(" + mAutoCorrectionThreshold + ")");
@@ -308,7 +306,7 @@ public class Suggest implements Dictionary.WordCallback {
if (typedWord != null) {
mSuggestions.add(0, typedWord.toString());
}
- if (mAutoTextEnabled) {
+ if (mQuickFixesEnabled) {
int i = 0;
int max = 6;
// Don't autotext the suggestions from the dictionaries
@@ -354,11 +352,30 @@ public class Suggest implements Dictionary.WordCallback {
}
}
removeDupes();
- return new SuggestedWords.Builder().addWords(mSuggestions, null);
- }
-
- public int[] getNextLettersFrequencies() {
- return mNextLettersFrequencies;
+ if (DBG) {
+ ArrayList<SuggestedWords.SuggestedWordInfo> frequencyInfoList =
+ new ArrayList<SuggestedWords.SuggestedWordInfo>();
+ frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo("+", false));
+ final int priorityLength = mPriorities.length;
+ for (int i = 0; i < priorityLength; ++i) {
+ if (normalizedScore > 0) {
+ final String priorityThreshold = Integer.toString(mPriorities[i]) + " (" +
+ normalizedScore + ")";
+ frequencyInfoList.add(
+ new SuggestedWords.SuggestedWordInfo(priorityThreshold, false));
+ normalizedScore = 0.0;
+ } else {
+ final String priority = Integer.toString(mPriorities[i]);
+ frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo(priority, false));
+ }
+ }
+ for (int i = priorityLength; i < mSuggestions.size(); ++i) {
+ frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo("--", false));
+ }
+ return new SuggestedWords.Builder().addWords(mSuggestions, frequencyInfoList);
+ } else {
+ return new SuggestedWords.Builder().addWords(mSuggestions, null);
+ }
}
private void removeDupes() {
@@ -392,12 +409,12 @@ public class Suggest implements Dictionary.WordCallback {
return mHasAutoCorrection;
}
- private boolean compareCaseInsensitive(final String mLowerOriginalWord,
+ private static boolean compareCaseInsensitive(final String lowerOriginalWord,
final char[] word, final int offset, final int length) {
- final int originalLength = mLowerOriginalWord.length();
+ final int originalLength = lowerOriginalWord.length();
if (originalLength == length && Character.isUpperCase(word[offset])) {
for (int i = 0; i < originalLength; i++) {
- if (mLowerOriginalWord.charAt(i) != Character.toLowerCase(word[offset+i])) {
+ if (lowerOriginalWord.charAt(i) != Character.toLowerCase(word[offset+i])) {
return false;
}
}
diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java
index 56ee5b9e7..c06bd736e 100644
--- a/java/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserDictionary.java
@@ -126,9 +126,8 @@ public class UserDictionary extends ExpandableDictionary {
}
@Override
- public synchronized void getWords(final WordComposer codes, final WordCallback callback,
- int[] nextLettersFrequencies) {
- super.getWords(codes, callback, nextLettersFrequencies);
+ public synchronized void getWords(final WordComposer codes, final WordCallback callback) {
+ super.getWords(codes, callback);
}
@Override
@@ -138,7 +137,7 @@ public class UserDictionary extends ExpandableDictionary {
private void addWords(Cursor cursor) {
clearDictionary();
-
+ if (cursor == null) return;
final int maxWordLength = getMaxWordLength();
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index e980d3a30..149c5ca9e 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -16,13 +16,17 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.keyboard.KeyboardId;
+
import android.inputmethodservice.InputMethodService;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
+import android.text.InputType;
import android.text.format.DateUtils;
import android.util.Log;
+import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
@@ -55,7 +59,7 @@ public class Utils {
}
public static class GCUtils {
- private static final String TAG = "GCUtils";
+ private static final String GC_TAG = GCUtils.class.getSimpleName();
public static final int GC_TRY_COUNT = 2;
// GC_TRY_LOOP_MAX is used for the hard limit of GC wait,
// GC_TRY_LOOP_MAX should be greater than GC_TRY_COUNT.
@@ -84,7 +88,7 @@ public class Utils {
Thread.sleep(GC_INTERVAL);
return true;
} catch (InterruptedException e) {
- Log.e(TAG, "Sleep was interrupted.");
+ Log.e(GC_TAG, "Sleep was interrupted.");
LatinImeLogger.logOnException(metaData, t);
return false;
}
@@ -261,6 +265,19 @@ public class Utils {
return dp[sl][tl];
}
+ // Get the current stack trace
+ public static String getStackTrace() {
+ StringBuilder sb = new StringBuilder();
+ try {
+ throw new RuntimeException();
+ } catch (RuntimeException e) {
+ StackTraceElement[] frames = e.getStackTrace();
+ // Start at 1 because the first frame is here and we don't care about it
+ for (int j = 1; j < frames.length; ++j) sb.append(frames[j].toString() + "\n");
+ }
+ return sb.toString();
+ }
+
// In dictionary.cpp, getSuggestion() method,
// suggestion scores are computed using the below formula.
// original score (called 'frequency')
@@ -268,13 +285,22 @@ public class Utils {
// (the number of matched characters between typed word and suggested word))
// * (individual word's score which defined in the unigram dictionary,
// and this score is defined in range [0, 255].)
- // * (when before.length() == after.length(),
- // mFullWordMultiplier (this is defined 2))
- // So, maximum original score is pow(2, before.length()) * 255 * 2
- // So, we can normalize original score by dividing this value.
+ // Then, the following processing is applied.
+ // - If the dictionary word is matched up to the point of the user entry
+ // (full match up to min(before.length(), after.length())
+ // => Then multiply by FULL_MATCHED_WORDS_PROMOTION_RATE (this is defined 1.2)
+ // - If the word is a true full match except for differences in accents or
+ // capitalization, then treat it as if the frequency was 255.
+ // - If before.length() == after.length()
+ // => multiply by mFullWordMultiplier (this is defined 2))
+ // So, maximum original score is pow(2, min(before.length(), after.length())) * 255 * 2 * 1.2
+ // For historical reasons we ignore the 1.2 modifier (because the measure for a good
+ // autocorrection threshold was done at a time when it didn't exist). This doesn't change
+ // the result.
+ // So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2.
private static final int MAX_INITIAL_SCORE = 255;
private static final int TYPED_LETTER_MULTIPLIER = 2;
- private static final int FULL_WORD_MULTIPLYER = 2;
+ private static final int FULL_WORD_MULTIPLIER = 2;
public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) {
final int beforeLength = before.length();
final int afterLength = after.length();
@@ -284,7 +310,7 @@ public class Utils {
// correction.
final double maximumScore = MAX_INITIAL_SCORE
* Math.pow(TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength))
- * FULL_WORD_MULTIPLYER;
+ * FULL_WORD_MULTIPLIER;
// add a weight based on edit distance.
// distance <= max(afterLength, beforeLength) == afterLength,
// so, 0 <= distance / afterLength <= 1
@@ -439,4 +465,24 @@ public class Utils {
return new PrintWriter(new FileOutputStream(mFile), true /* autoFlush */);
}
}
+
+ // Please refer to TextView.isPasswordInputType
+ public static boolean isPasswordInputType(int inputType) {
+ final int variation =
+ inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
+ return (variation
+ == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD))
+ || (variation
+ == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD))
+ || (variation
+ == (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
+ }
+
+ // Please refer to TextView.isVisiblePasswordInputType
+ public static boolean isVisiblePasswordInputType(int inputType) {
+ final int variation =
+ inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
+ return variation
+ == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 2e415b771..e003dcd5b 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,12 +16,16 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.keyboard.KeyDetector;
+
import java.util.ArrayList;
/**
* A place to store the currently composing word with information such as adjacent key codes as well
*/
public class WordComposer {
+ public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
+
/**
* The list of unicode values for each keystroke (including surrounding keys)
*/
diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
index 61a194a8d..277ef7e65 100644
--- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
+++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
@@ -38,16 +38,13 @@ import android.os.IBinder;
import android.preference.PreferenceManager;
import android.provider.Browser;
import android.speech.SpeechRecognizer;
-import android.text.Layout;
-import android.text.Selection;
-import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
-import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
@@ -83,9 +80,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
private static final String IME_OPTION_NO_MICROPHONE = "nm";
private static final int RECOGNITIONVIEW_HEIGHT_THRESHOLD_RATIO = 6;
- @SuppressWarnings("unused")
- private static final String TAG = "VoiceIMEConnector";
- private static boolean DEBUG = LatinImeLogger.sDBG;
+ private static final String TAG = VoiceIMEConnector.class.getSimpleName();
+ private static final boolean DEBUG = LatinImeLogger.sDBG;
private boolean mAfterVoiceInput;
private boolean mHasUsedVoiceInput;
@@ -177,7 +173,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
return;
}
- AlertDialog.Builder builder = new AlertDialog.Builder(mService);
+ AlertDialog.Builder builder = new UrlLinkAlertDialogBuilder(mService);
builder.setCancelable(true);
builder.setIcon(R.drawable.ic_mic_dialog);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -215,90 +211,80 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mService.getText(R.string.voice_warning_how_to_turn_off));
}
builder.setMessage(message);
-
builder.setTitle(R.string.voice_warning_title);
mVoiceWarningDialog = builder.create();
- Window window = mVoiceWarningDialog.getWindow();
- WindowManager.LayoutParams lp = window.getAttributes();
+ final Window window = mVoiceWarningDialog.getWindow();
+ final WindowManager.LayoutParams lp = window.getAttributes();
lp.token = token;
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
window.setAttributes(lp);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
mVoiceInput.logKeyboardWarningDialogShown();
mVoiceWarningDialog.show();
- // Make URL in the dialog message clickable
- TextView textView = (TextView) mVoiceWarningDialog.findViewById(android.R.id.message);
- if (textView != null) {
- final CustomLinkMovementMethod method = CustomLinkMovementMethod.getInstance();
- method.setVoiceWarningDialog(mVoiceWarningDialog);
- textView.setMovementMethod(method);
- }
}
- private static class CustomLinkMovementMethod extends LinkMovementMethod {
- private static CustomLinkMovementMethod sLinkMovementMethodInstance =
- new CustomLinkMovementMethod();
+ private static class UrlLinkAlertDialogBuilder extends AlertDialog.Builder {
private AlertDialog mAlertDialog;
- public void setVoiceWarningDialog(AlertDialog alertDialog) {
- mAlertDialog = alertDialog;
+ public UrlLinkAlertDialogBuilder(Context context) {
+ super(context);
}
- public static CustomLinkMovementMethod getInstance() {
- return sLinkMovementMethodInstance;
+ @Override
+ public AlertDialog.Builder setMessage(CharSequence message) {
+ return super.setMessage(replaceURLSpan(message));
+ }
+
+ private Spanned replaceURLSpan(CharSequence message) {
+ // Replace all spans with the custom span
+ final SpannableStringBuilder ssb = new SpannableStringBuilder(message);
+ for (URLSpan span : ssb.getSpans(0, ssb.length(), URLSpan.class)) {
+ int spanStart = ssb.getSpanStart(span);
+ int spanEnd = ssb.getSpanEnd(span);
+ int spanFlags = ssb.getSpanFlags(span);
+ ssb.removeSpan(span);
+ ssb.setSpan(new ClickableSpan(span.getURL()), spanStart, spanEnd, spanFlags);
+ }
+ return ssb;
}
- // Almost the same as LinkMovementMethod.onTouchEvent(), but overrides it for
- // FLAG_ACTIVITY_NEW_TASK and mAlertDialog.cancel().
@Override
- public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
- int action = event.getAction();
-
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
- int x = (int) event.getX();
- int y = (int) event.getY();
-
- x -= widget.getTotalPaddingLeft();
- y -= widget.getTotalPaddingTop();
-
- x += widget.getScrollX();
- y += widget.getScrollY();
-
- Layout layout = widget.getLayout();
- int line = layout.getLineForVertical(y);
- int off = layout.getOffsetForHorizontal(line, x);
-
- ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
-
- if (link.length != 0) {
- if (action == MotionEvent.ACTION_UP) {
- if (link[0] instanceof URLSpan) {
- URLSpan urlSpan = (URLSpan) link[0];
- Uri uri = Uri.parse(urlSpan.getURL());
- Context context = widget.getContext();
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
- if (mAlertDialog != null) {
- // Go back to the previous IME for now.
- // TODO: If we can find a way to bring the new activity to front
- // while keeping the warning dialog, we don't need to cancel here.
- mAlertDialog.cancel();
- }
- context.startActivity(intent);
- } else {
- link[0].onClick(widget);
- }
- } else if (action == MotionEvent.ACTION_DOWN) {
- Selection.setSelection(buffer, buffer.getSpanStart(link[0]),
- buffer.getSpanEnd(link[0]));
+ public AlertDialog create() {
+ final AlertDialog dialog = super.create();
+
+ dialog.setOnShowListener(new DialogInterface.OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialogInterface) {
+ // Make URL in the dialog message click-able.
+ TextView textView = (TextView) mAlertDialog.findViewById(android.R.id.message);
+ if (textView != null) {
+ textView.setMovementMethod(LinkMovementMethod.getInstance());
}
- return true;
- } else {
- Selection.removeSelection(buffer);
}
+ });
+ mAlertDialog = dialog;
+ return dialog;
+ }
+
+ class ClickableSpan extends URLSpan {
+ public ClickableSpan(String url) {
+ super(url);
+ }
+
+ @Override
+ public void onClick(View widget) {
+ Uri uri = Uri.parse(getURL());
+ Context context = widget.getContext();
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ // Add this flag to start an activity from service
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+ // Dismiss the warning dialog and go back to the previous IME.
+ // TODO: If we can find a way to bring the new activity to front while keeping
+ // the warning dialog, we don't need to dismiss it here.
+ mAlertDialog.cancel();
+ context.startActivity(intent);
}
- return super.onTouchEvent(widget, buffer, event);
}
}
@@ -729,7 +715,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mHandler.updateVoiceResults();
}
- public FieldContext makeFieldContext() {
+ private FieldContext makeFieldContext() {
SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
return new FieldContext(mService.getCurrentInputConnection(),
mService.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),