aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/AndroidManifest.xml1
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java323
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java323
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java11
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java4
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestionsView.java28
-rw-r--r--java/src/com/android/inputmethod/latin/UserDictionary.java60
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java67
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java195
10 files changed, 542 insertions, 474 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index b0525326c..888d73f5c 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -5,7 +5,6 @@
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
- <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application android:label="@string/english_ime_name"
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 71a71d6fd..734189689 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -44,7 +43,8 @@ import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
-public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
+public class KeyboardSwitcher implements KeyboardState.SwitchActions,
+ SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
public static final boolean DEBUG_STATE = false;
@@ -69,9 +69,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private Resources mResources;
private KeyboardState mState;
- private static final int UNSHIFT = 0;
- private static final int MANUAL_SHIFT = 1;
- private static final int AUTOMATIC_SHIFT = 2;
private KeyboardId mMainKeyboardId;
private KeyboardId mSymbolsKeyboardId;
@@ -81,74 +78,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
- private KeyboardLayoutState mSavedKeyboardState = new KeyboardLayoutState();
-
/** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
* what user actually typed. */
private boolean mIsAutoCorrectionActive;
- // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState
- // and ModifierKeyState into KeyboardState.
- private static final int SWITCH_STATE_ALPHA = 0;
- private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
- private static final int SWITCH_STATE_SYMBOL = 2;
- // The following states are used only on the distinct multi-touch panel devices.
- private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
- private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
- private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
- private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
- private int mSwitchState = SWITCH_STATE_ALPHA;
-
- private String mLayoutSwitchBackSymbols;
-
private int mThemeIndex = -1;
private Context mThemeContext;
private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
- // TODO: Move this to KeyboardState.
- private class KeyboardLayoutState {
- private boolean mIsValid;
- private boolean mIsAlphabetMode;
- private boolean mIsShiftLocked;
- private boolean mIsShifted;
-
- public void save() {
- mIsAlphabetMode = isAlphabetMode();
- if (mIsAlphabetMode) {
- mIsShiftLocked = mState.isShiftLocked();
- mIsShifted = !mIsShiftLocked && mState.isShiftedOrShiftLocked();
- } else {
- mIsShiftLocked = false;
- mIsShifted = isSymbolShifted();
- }
- mIsValid = true;
- }
-
- public void restore() {
- mPrevMainKeyboardWasShiftLocked = false;
- if (!mIsValid || mIsAlphabetMode) {
- setAlphabetKeyboard();
- } else {
- if (mIsShifted) {
- setSymbolsShiftedKeyboard();
- } else {
- setSymbolsKeyboard();
- }
- }
-
- if (!mIsValid) return;
- mIsValid = false;
-
- if (mIsAlphabetMode) {
- setShiftLocked(mIsShiftLocked);
- if (!mIsShiftLocked) {
- setShifted(mIsShifted ? MANUAL_SHIFT : UNSHIFT);
- }
- }
- }
- }
-
public static KeyboardSwitcher getInstance() {
return sInstance;
}
@@ -167,7 +105,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mResources = ims.getResources();
mPrefs = prefs;
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
- mState = new KeyboardState();
+ mState = new KeyboardState(this);
setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs));
prefs.registerOnSharedPreferenceChangeListener(this);
}
@@ -199,9 +137,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues);
mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues);
mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
- mState.onLoadKeyboard();
- mLayoutSwitchBackSymbols = mResources.getString(R.string.layout_switch_back_symbols);
- mSavedKeyboardState.restore();
+ mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols));
} catch (RuntimeException e) {
Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
@@ -210,7 +146,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
public void saveKeyboardState() {
if (mCurrentId != null) {
- mSavedKeyboardState.save();
+ mState.onSaveKeyboardState(isAlphabetMode(), isSymbolShifted());
}
}
@@ -227,7 +163,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mKeyboardView.setKeyboard(keyboard);
mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
mCurrentId = keyboard.mId;
- mSwitchState = getSwitchState();
+ mState.onSetKeyboard(isAlphabetMode());
updateShiftLockState(keyboard);
mKeyboardView.setKeyPreviewPopupEnabled(
Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources),
@@ -238,10 +174,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
updateShiftState();
}
- private int getSwitchState() {
- return isAlphabetMode() ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
- }
-
private void updateShiftLockState(Keyboard keyboard) {
if (mCurrentId.equals(mSymbolsShiftedKeyboardId)) {
// Symbol keyboard may have an ALT key that has a caps lock style indicator (a.k.a.
@@ -346,6 +278,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT;
}
+ // TODO: Delegate to KeyboardState
public boolean isAlphabetMode() {
return mCurrentId != null && mCurrentId.isAlphabetKeyboard();
}
@@ -377,7 +310,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mState.isManualTemporaryUpperCase();
}
- private void setShifted(int shiftMode) {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setShifted(int shiftMode) {
mInputMethodService.mHandler.cancelUpdateShiftState();
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard == null)
@@ -401,7 +336,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mKeyboardView.invalidateAllKeys();
}
- private void setShiftLocked(boolean shiftLocked) {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setShiftLocked(boolean shiftLocked) {
mInputMethodService.mHandler.cancelUpdateShiftState();
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard == null)
@@ -427,10 +364,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (isAlphabetMode()) {
setShifted(mState.isShiftedOrShiftLocked() ? UNSHIFT : MANUAL_SHIFT);
} else {
- toggleShiftInSymbols();
+ if (isSymbolShifted()) {
+ setSymbolsKeyboard();
+ } else {
+ setSymbolsShiftedKeyboard();
+ }
}
}
+ /**
+ * Toggle caps lock state triggered by user touch event.
+ */
public void toggleCapsLock() {
if (DEBUG_STATE) {
Log.d(TAG, "toggleCapsLock: " + mState);
@@ -448,11 +392,18 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
}
+ /**
+ * Toggle keyboard mode triggered by user touch event.
+ */
public void toggleKeyboardMode() {
if (DEBUG_STATE) {
- Log.d(TAG, "toggleKeyboard: " + mState);
+ Log.d(TAG, "toggleKeyboardMode: " + mState);
+ }
+ if (isAlphabetMode()) {
+ setSymbolsKeyboard();
+ } else {
+ setAlphabetKeyboard();
}
- toggleAlphabetAndSymbols();
}
/**
@@ -463,19 +414,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
Log.d(TAG, "updateShiftState: " + mState
+ " autoCaps=" + mInputMethodService.getCurrentAutoCapsState());
}
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = mState.isShiftLocked();
- if (isAlphabetMode) {
- if (!isShiftLocked && !mState.isShiftKeyIgnoring()) {
- if (mState.isShiftKeyReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
- // Only when shift key is releasing, automatic temporary upper case will be set.
- setShifted(AUTOMATIC_SHIFT);
- } else {
- setShifted(mState.isShiftKeyMomentary() ? MANUAL_SHIFT : UNSHIFT);
- }
- }
- }
- mState.onUpdateShiftState(isAlphabetMode);
+ mState.onUpdateShiftState(isAlphabetMode(), mInputMethodService.getCurrentAutoCapsState());
}
public void onPressShift(boolean withSliding) {
@@ -484,33 +423,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (DEBUG_STATE) {
Log.d(TAG, "onPressShift: " + mState + " sliding=" + withSliding);
}
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = mState.isShiftLocked();
- final boolean isAutomaticTemporaryUpperCase = mState.isAutomaticTemporaryUpperCase();
- final boolean isShiftedOrShiftLocked = mState.isShiftedOrShiftLocked();
- if (isAlphabetMode) {
- if (isShiftLocked) {
- // Shift key is pressed while caps lock state, we will treat this state as shifted
- // caps lock state and mark as if shift key pressed while normal state.
- setShifted(MANUAL_SHIFT);
- } else if (isAutomaticTemporaryUpperCase) {
- // Shift key is pressed while automatic temporary upper case, we have to move to
- // manual temporary upper case.
- setShifted(MANUAL_SHIFT);
- } else if (isShiftedOrShiftLocked) {
- // In manual upper case state, we just record shift key has been pressing while
- // shifted state.
- } else {
- // In base layout, chording or manual temporary upper case mode is started.
- setShifted(MANUAL_SHIFT);
- }
- } else {
- // In symbol mode, just toggle symbol and symbol more keyboard.
- toggleShiftInSymbols();
- mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
- }
- mState.onPressShift(isAlphabetMode, isShiftLocked, isAutomaticTemporaryUpperCase,
- isShiftedOrShiftLocked);
+ mState.onPressShift(isAlphabetMode(), isSymbolShifted());
}
public void onReleaseShift(boolean withSliding) {
@@ -519,61 +432,21 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (DEBUG_STATE) {
Log.d(TAG, "onReleaseShift: " + mState + " sliding=" + withSliding);
}
- final boolean isAlphabetMode = isAlphabetMode();
- final boolean isShiftLocked = mState.isShiftLocked();
- final boolean isShiftLockShifted = mState.isShiftLockShifted();
- final boolean isShiftedOrShiftLocked = mState.isShiftedOrShiftLocked();
- final boolean isManualTemporaryUpperCaseFromAuto =
- mState.isManualTemporaryUpperCaseFromAuto();
- if (isAlphabetMode) {
- if (mState.isShiftKeyMomentary()) {
- // After chording input while normal state.
- setShifted(UNSHIFT);
- } else if (isShiftLocked && !isShiftLockShifted && (mState.isShiftKeyPressing()
- || mState.isShiftKeyPressingOnShifted()) && !withSliding) {
- // Shift has been long pressed, ignore this release.
- } else if (isShiftLocked && !mState.isShiftKeyIgnoring() && !withSliding) {
- // Shift has been pressed without chording while caps lock state.
- setShiftLocked(false);
- } else if (isShiftedOrShiftLocked && mState.isShiftKeyPressingOnShifted()
- && !withSliding) {
- // Shift has been pressed without chording while shifted state.
- setShifted(UNSHIFT);
- } else if (isManualTemporaryUpperCaseFromAuto && mState.isShiftKeyPressing()
- && !withSliding) {
- // Shift has been pressed without chording while manual temporary upper case
- // transited from automatic temporary upper case.
- setShifted(UNSHIFT);
- }
- } else {
- // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
- // key and another key, then releases the shift key.
- if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
- toggleShiftInSymbols();
- }
- }
- mState.onReleaseShift();
+ mState.onReleaseShift(isAlphabetMode(), isSymbolShifted(), withSliding);
}
public void onPressSymbol() {
if (DEBUG_STATE) {
Log.d(TAG, "onPressSymbol: " + mState);
}
- toggleAlphabetAndSymbols();
- mState.onPressSymbol();
- mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
+ mState.onPressSymbol(isAlphabetMode());
}
public void onReleaseSymbol() {
if (DEBUG_STATE) {
Log.d(TAG, "onReleaseSymbol: " + mState);
- }
- // Snap back to the previous keyboard mode if the user chords the mode change key and
- // another key, then releases the mode change key.
- if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
- toggleAlphabetAndSymbols();
}
- mState.onReleaseSymbol();
+ mState.onReleaseSymbol(isAlphabetMode());
}
public void onOtherKeyPressed() {
@@ -584,57 +457,36 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
public void onCancelInput() {
- // Snap back to the previous keyboard mode if the user cancels sliding input.
- if (isSinglePointer()) {
- if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
- toggleAlphabetAndSymbols();
- } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
- toggleShiftInSymbols();
- }
- }
+ mState.onCancelInput(isAlphabetMode(), isSymbolShifted(), isSinglePointer());
}
- // TODO: Move this variable to KeyboardState.
- private boolean mPrevMainKeyboardWasShiftLocked;
-
- private void setSymbolsKeyboard() {
- mPrevMainKeyboardWasShiftLocked = mState.isShiftLocked();
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setSymbolsKeyboard() {
+ mState.onSaveShiftLockState();
setKeyboard(getKeyboard(mSymbolsKeyboardId));
}
- private void setAlphabetKeyboard() {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setAlphabetKeyboard() {
setKeyboard(getKeyboard(mMainKeyboardId));
- setShiftLocked(mPrevMainKeyboardWasShiftLocked);
- mPrevMainKeyboardWasShiftLocked = false;
- }
-
- private void toggleAlphabetAndSymbols() {
- if (isAlphabetMode()) {
- setSymbolsKeyboard();
- } else {
- setAlphabetKeyboard();
- }
+ mState.onRestoreShiftLockState();
}
+ // TODO: Remove this method
private boolean isSymbolShifted() {
return mCurrentId != null && mCurrentId.equals(mSymbolsShiftedKeyboardId);
}
- private void setSymbolsShiftedKeyboard() {
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setSymbolsShiftedKeyboard() {
setKeyboard(getKeyboard(mSymbolsShiftedKeyboardId));
}
- private void toggleShiftInSymbols() {
- if (isSymbolShifted()) {
- setSymbolsKeyboard();
- } else {
- setSymbolsShiftedKeyboard();
- }
- }
-
public boolean isInMomentarySwitchState() {
- return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
- || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
+ return mState.isInMomentarySwitchState();
}
public boolean isVibrateAndSoundFeedbackRequired() {
@@ -649,84 +501,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch();
}
- private static boolean isSpaceCharacter(int c) {
- return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
- }
-
- private boolean isLayoutSwitchBackCharacter(int c) {
- if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false;
- if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true;
- return false;
- }
-
/**
* Updates state machine to figure out when to automatically snap back to the previous mode.
*/
- public void onKey(int code) {
+ public void onCodeInput(int code) {
if (DEBUG_STATE) {
- Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState
- + " isSinglePointer=" + isSinglePointer());
- }
- switch (mSwitchState) {
- case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
- // Only distinct multi touch devices can be in this state.
- // On non-distinct multi touch devices, mode change key is handled by
- // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
- // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
- // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
- // {@link #SWITCH_STATE_MOMENTARY}.
- if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
- // Detected only the mode change key has been pressed, and then released.
- if (mCurrentId.equals(mMainKeyboardId)) {
- mSwitchState = SWITCH_STATE_ALPHA;
- } else {
- mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
- }
- } else if (isSinglePointer()) {
- // Snap back to the previous keyboard mode if the user pressed the mode change key
- // and slid to other key, then released the finger.
- // If the user cancels the sliding input, snapping back to the previous keyboard
- // mode is handled by {@link #onCancelInput}.
- toggleAlphabetAndSymbols();
- } else {
- // Chording input is being started. The keyboard mode will be snapped back to the
- // previous mode in {@link onReleaseSymbol} when the mode change key is released.
- mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
- }
- break;
- case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
- if (code == Keyboard.CODE_SHIFT) {
- // Detected only the shift key has been pressed on symbol layout, and then released.
- mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
- } else if (isSinglePointer()) {
- // Snap back to the previous keyboard mode if the user pressed the shift key on
- // symbol mode and slid to other key, then released the finger.
- toggleShiftInSymbols();
- mSwitchState = SWITCH_STATE_SYMBOL;
- } else {
- // Chording input is being started. The keyboard mode will be snapped back to the
- // previous mode in {@link onReleaseShift} when the shift key is released.
- mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
- }
- break;
- case SWITCH_STATE_SYMBOL_BEGIN:
- if (!isSpaceCharacter(code) && code >= 0) {
- mSwitchState = SWITCH_STATE_SYMBOL;
- }
- // Snap back to alpha keyboard mode immediately if user types a quote character.
- if (isLayoutSwitchBackCharacter(code)) {
- setAlphabetKeyboard();
- }
- break;
- case SWITCH_STATE_SYMBOL:
- case SWITCH_STATE_CHORDING_SYMBOL:
- // Snap back to alpha keyboard mode if user types one or more non-space/enter
- // characters followed by a space/enter or a quote character.
- if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
- setAlphabetKeyboard();
- }
- break;
+ Log.d(TAG, "onCodeInput: code=" + code + " isSinglePointer=" + isSinglePointer()
+ + " " + mState);
}
+ mState.onCodeInput(isAlphabetMode(), isSymbolShifted(), code, isSinglePointer());
}
public LatinKeyboardView getKeyboardView() {
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 6c5c3e7be..778aac3de 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -65,12 +65,12 @@ public class ProximityInfo {
return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null);
}
- public static ProximityInfo createSpellCheckerProximityInfo() {
+ public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) {
final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo();
spellCheckerProximityInfo.mNativeProximityInfo =
spellCheckerProximityInfo.setProximityInfoNative(
SpellCheckerProximityInfo.ROW_SIZE,
- 480, 300, 10, 3, SpellCheckerProximityInfo.PROXIMITY,
+ 480, 300, 11, 3, proximity,
0, null, null, null, null, null, null, null, null);
return spellCheckerProximityInfo;
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index e56159405..95c9162ef 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -16,22 +16,119 @@
package com.android.inputmethod.keyboard.internal;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.inputmethod.keyboard.Keyboard;
+
// TODO: Add unit tests
public class KeyboardState {
+ private static final String TAG = KeyboardState.class.getSimpleName();
+ private static final boolean DEBUG_STATE = false;
+
+ public interface SwitchActions {
+ public void setAlphabetKeyboard();
+ public static final int UNSHIFT = 0;
+ public static final int MANUAL_SHIFT = 1;
+ public static final int AUTOMATIC_SHIFT = 2;
+ public void setShifted(int shiftMode);
+ public void setShiftLocked(boolean shiftLocked);
+ public void setSymbolsKeyboard();
+ public void setSymbolsShiftedKeyboard();
+ }
+
private KeyboardShiftState mKeyboardShiftState = new KeyboardShiftState();
- // TODO: Combine these key state objects with auto mode switch state.
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
- public KeyboardState() {
+ private static final int SWITCH_STATE_ALPHA = 0;
+ private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
+ private static final int SWITCH_STATE_SYMBOL = 2;
+ // The following states are used only on the distinct multi-touch panel devices.
+ private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
+ private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
+ private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
+ private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
+ private int mSwitchState = SWITCH_STATE_ALPHA;
+
+ private String mLayoutSwitchBackSymbols;
+
+ private final SwitchActions mSwitchActions;
+
+ private final SavedKeyboardState mSavedKeyboardState = new SavedKeyboardState();
+ private boolean mPrevMainKeyboardWasShiftLocked;
+
+ private static class SavedKeyboardState {
+ public boolean mIsValid;
+ public boolean mIsAlphabetMode;
+ public boolean mIsShiftLocked;
+ public boolean mIsShifted;
}
- public void onLoadKeyboard() {
+ public KeyboardState(SwitchActions switchActions) {
+ mSwitchActions = switchActions;
+ }
+
+ public void onLoadKeyboard(String layoutSwitchBackSymbols) {
+ mLayoutSwitchBackSymbols = layoutSwitchBackSymbols;
mKeyboardShiftState.setShifted(false);
mKeyboardShiftState.setShiftLocked(false);
mShiftKeyState.onRelease();
mSymbolKeyState.onRelease();
+ mPrevMainKeyboardWasShiftLocked = false;
+ onRestoreKeyboardState();
+ }
+
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onSaveKeyboardState(boolean isAlphabetMode, boolean isSymbolShifted) {
+ final SavedKeyboardState state = mSavedKeyboardState;
+ state.mIsAlphabetMode = isAlphabetMode;
+ if (isAlphabetMode) {
+ state.mIsShiftLocked = isShiftLocked();
+ state.mIsShifted = !state.mIsShiftLocked && isShiftedOrShiftLocked();
+ } else {
+ state.mIsShiftLocked = false;
+ state.mIsShifted = isSymbolShifted;
+ }
+ state.mIsValid = true;
+ if (DEBUG_STATE) {
+ Log.d(TAG, "save: alphabet=" + state.mIsAlphabetMode
+ + " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
+ }
+ }
+
+ private void onRestoreKeyboardState() {
+ final SavedKeyboardState state = mSavedKeyboardState;
+ if (DEBUG_STATE) {
+ Log.d(TAG, "restore: valid=" + state.mIsValid + " alphabet=" + state.mIsAlphabetMode
+ + " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
+ }
+ if (!state.mIsValid || state.mIsAlphabetMode) {
+ mSwitchActions.setAlphabetKeyboard();
+ } else {
+ if (state.mIsShifted) {
+ mSwitchActions.setSymbolsShiftedKeyboard();
+ } else {
+ mSwitchActions.setSymbolsKeyboard();
+ }
+ }
+
+ if (!state.mIsValid) return;
+ state.mIsValid = false;
+
+ if (state.mIsAlphabetMode) {
+ mSwitchActions.setShiftLocked(state.mIsShiftLocked);
+ if (!state.mIsShiftLocked) {
+ mSwitchActions.setShifted(
+ state.mIsShifted ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+ }
+ }
+ }
+
+ // TODO: Get rid of this method
+ public void onSetKeyboard(boolean isAlphabetMode) {
+ mSwitchState = isAlphabetMode ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
}
public boolean isShiftLocked() {
@@ -73,40 +170,50 @@ public class KeyboardState {
mKeyboardShiftState.setAutomaticTemporaryUpperCase();
}
- // TODO: Get rid of this method
- public boolean isShiftKeyIgnoring() {
- return mShiftKeyState.isIgnoring();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyReleasing() {
- return mShiftKeyState.isReleasing();
+ private void toggleAlphabetAndSymbols(boolean isAlphabetMode) {
+ if (isAlphabetMode) {
+ mSwitchActions.setSymbolsKeyboard();
+ } else {
+ mSwitchActions.setAlphabetKeyboard();
+ }
}
- // TODO: Get rid of this method
- public boolean isShiftKeyMomentary() {
- return mShiftKeyState.isMomentary();
+ private void toggleShiftInSymbols(boolean isSymbolShifted) {
+ if (isSymbolShifted) {
+ mSwitchActions.setSymbolsKeyboard();
+ } else {
+ mSwitchActions.setSymbolsShiftedKeyboard();
+ }
}
- // TODO: Get rid of this method
- public boolean isShiftKeyPressing() {
- return mShiftKeyState.isPressing();
+ public void onRestoreShiftLockState() {
+ mSwitchActions.setShiftLocked(mPrevMainKeyboardWasShiftLocked);
+ mPrevMainKeyboardWasShiftLocked = false;
}
- // TODO: Get rid of this method
- public boolean isShiftKeyPressingOnShifted() {
- return mShiftKeyState.isPressingOnShifted();
+ public void onSaveShiftLockState() {
+ mPrevMainKeyboardWasShiftLocked = isShiftLocked();
}
+ // TODO: Remove this method.
public void onReleaseCapsLock() {
mShiftKeyState.onRelease();
}
- public void onPressSymbol() {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onPressSymbol(boolean isAlphabetMode) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
mSymbolKeyState.onPress();
+ mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
}
- public void onReleaseSymbol() {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onReleaseSymbol(boolean isAlphabetMode) {
+ // Snap back to the previous keyboard mode if the user chords the mode change key and
+ // another key, then releases the mode change key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ }
mSymbolKeyState.onRelease();
}
@@ -115,48 +222,200 @@ public class KeyboardState {
mSymbolKeyState.onOtherKeyPressed();
}
- public void onUpdateShiftState(boolean isAlphabetMode) {
- if (!isAlphabetMode) {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onUpdateShiftState(boolean isAlphabetMode, boolean autoCaps) {
+ if (isAlphabetMode) {
+ if (!isShiftLocked() && !mShiftKeyState.isIgnoring()) {
+ if (mShiftKeyState.isReleasing() && autoCaps) {
+ // Only when shift key is releasing, automatic temporary upper case will be set.
+ mSwitchActions.setShifted(SwitchActions.AUTOMATIC_SHIFT);
+ } else {
+ mSwitchActions.setShifted(mShiftKeyState.isMomentary()
+ ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+ }
+ }
+ } else {
// In symbol keyboard mode, we should clear shift key state because only alphabet
// keyboard has shift key.
mSymbolKeyState.onRelease();
}
}
- // TODO: Get rid of these boolean arguments.
- public void onPressShift(boolean isAlphabetMode, boolean isShiftLocked,
- boolean isAutomaticTemporaryUpperCase, boolean isShiftedOrShiftLocked) {
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onPressShift(boolean isAlphabetMode, boolean isSymbolShifted) {
if (isAlphabetMode) {
- if (isShiftLocked) {
+ if (isShiftLocked()) {
// Shift key is pressed while caps lock state, we will treat this state as shifted
// caps lock state and mark as if shift key pressed while normal state.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isAutomaticTemporaryUpperCase) {
+ } else if (isAutomaticTemporaryUpperCase()) {
// Shift key is pressed while automatic temporary upper case, we have to move to
// manual temporary upper case.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isShiftedOrShiftLocked) {
+ } else if (isShiftedOrShiftLocked()) {
// In manual upper case state, we just record shift key has been pressing while
// shifted state.
mShiftKeyState.onPressOnShifted();
} else {
// In base layout, chording or manual temporary upper case mode is started.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
}
} else {
// In symbol mode, just toggle symbol and symbol more keyboard.
+ toggleShiftInSymbols(isSymbolShifted);
+ mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
mShiftKeyState.onPress();
}
}
- public void onReleaseShift() {
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onReleaseShift(boolean isAlphabetMode, boolean isSymbolShifted,
+ boolean withSliding) {
+ if (isAlphabetMode) {
+ final boolean isShiftLocked = isShiftLocked();
+ if (mShiftKeyState.isMomentary()) {
+ // After chording input while normal state.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ } else if (isShiftLocked && !isShiftLockShifted() && (mShiftKeyState.isPressing()
+ || mShiftKeyState.isPressingOnShifted()) && !withSliding) {
+ // Shift has been long pressed, ignore this release.
+ } else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) {
+ // Shift has been pressed without chording while caps lock state.
+ mSwitchActions.setShiftLocked(false);
+ } else if (isShiftedOrShiftLocked() && mShiftKeyState.isPressingOnShifted()
+ && !withSliding) {
+ // Shift has been pressed without chording while shifted state.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ } else if (isManualTemporaryUpperCaseFromAuto() && mShiftKeyState.isPressing()
+ && !withSliding) {
+ // Shift has been pressed without chording while manual temporary upper case
+ // transited from automatic temporary upper case.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ }
+ } else {
+ // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
+ // key and another key, then releases the shift key.
+ if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
+ toggleShiftInSymbols(isSymbolShifted);
+ }
+ }
mShiftKeyState.onRelease();
}
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onCancelInput(boolean isAlphabetMode, boolean isSymbolShifted,
+ boolean isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user cancels sliding input.
+ if (isSinglePointer) {
+ if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
+ toggleShiftInSymbols(isSymbolShifted);
+ }
+ }
+ }
+
+ public boolean isInMomentarySwitchState() {
+ return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
+ || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
+ }
+
+ private static boolean isSpaceCharacter(int c) {
+ return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
+ }
+
+ private boolean isLayoutSwitchBackCharacter(int c) {
+ if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false;
+ if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true;
+ return false;
+ }
+
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onCodeInput(boolean isAlphabetMode, boolean isSymbolShifted, int code,
+ boolean isSinglePointer) {
+ switch (mSwitchState) {
+ case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
+ // Only distinct multi touch devices can be in this state.
+ // On non-distinct multi touch devices, mode change key is handled by
+ // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
+ // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
+ // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
+ // {@link #SWITCH_STATE_MOMENTARY}.
+ if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ // Detected only the mode change key has been pressed, and then released.
+ if (isAlphabetMode) {
+ mSwitchState = SWITCH_STATE_ALPHA;
+ } else {
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ }
+ } else if (isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user pressed the mode change key
+ // and slid to other key, then released the finger.
+ // If the user cancels the sliding input, snapping back to the previous keyboard
+ // mode is handled by {@link #onCancelInput}.
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ } else {
+ // Chording input is being started. The keyboard mode will be snapped back to the
+ // previous mode in {@link onReleaseSymbol} when the mode change key is released.
+ mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
+ }
+ break;
+ case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
+ if (code == Keyboard.CODE_SHIFT) {
+ // Detected only the shift key has been pressed on symbol layout, and then released.
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ } else if (isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user pressed the shift key on
+ // symbol mode and slid to other key, then released the finger.
+ toggleShiftInSymbols(isSymbolShifted);
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ } else {
+ // Chording input is being started. The keyboard mode will be snapped back to the
+ // previous mode in {@link onReleaseShift} when the shift key is released.
+ mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
+ }
+ break;
+ case SWITCH_STATE_SYMBOL_BEGIN:
+ if (!isSpaceCharacter(code) && code >= 0) {
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ }
+ // Snap back to alpha keyboard mode immediately if user types a quote character.
+ if (isLayoutSwitchBackCharacter(code)) {
+ mSwitchActions.setAlphabetKeyboard();
+ }
+ break;
+ case SWITCH_STATE_SYMBOL:
+ case SWITCH_STATE_CHORDING_SYMBOL:
+ // Snap back to alpha keyboard mode if user types one or more non-space/enter
+ // characters followed by a space/enter or a quote character.
+ if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
+ mSwitchActions.setAlphabetKeyboard();
+ }
+ break;
+ }
+ }
+
+ private static String switchStateToString(int switchState) {
+ switch (switchState) {
+ case SWITCH_STATE_ALPHA: return "ALPHA";
+ case SWITCH_STATE_SYMBOL_BEGIN: return "SYMBOL-BEGIN";
+ case SWITCH_STATE_SYMBOL: return "SYMBOL";
+ case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: return "MOMENTARY-ALPHA-SYMBOL";
+ case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: return "MOMENTARY-SYMBOL-MORE";
+ case SWITCH_STATE_CHORDING_ALPHA: return "CHORDING-ALPHA";
+ case SWITCH_STATE_CHORDING_SYMBOL: return "CHORDING-SYMBOL";
+ default: return null;
+ }
+ }
+
@Override
public String toString() {
return "[keyboard=" + mKeyboardShiftState
+ " shift=" + mShiftKeyState
- + " symbol=" + mSymbolKeyState + "]";
+ + " symbol=" + mSymbolKeyState
+ + " switch=" + switchStateToString(mSwitchState) + "]";
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index c2656b891..5ee69d1c4 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1374,7 +1374,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mExpectingUpdateSelection = true;
break;
}
- switcher.onKey(primaryCode);
+ switcher.onCodeInput(primaryCode);
// Reset after any single keystroke
mEnteredText = null;
}
@@ -1390,7 +1390,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
ic.commitText(text, 1);
ic.endBatchEdit();
mKeyboardSwitcher.updateShiftState();
- mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
+ mKeyboardSwitcher.onCodeInput(Keyboard.CODE_DUMMY);
mSpaceState = SPACE_STATE_NONE;
mEnteredText = text;
}
@@ -2396,11 +2396,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// TODO: cleanup messy flags
final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
&& !mInputTypeNoAutoCorrect;
- mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled)
- ? Suggest.CORRECTION_FULL
- : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
- mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect
- && mSettingsValues.mAutoCorrectEnabled)
+ mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE;
+ mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect)
? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
if (mSuggest != null) {
mSuggest.setCorrectionMode(mCorrectionMode);
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 2a36f8266..b618ca7ed 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -171,10 +171,6 @@ public class Suggest implements Dictionary.WordCallback {
}.start();
}
- public int getCorrectionMode() {
- return mCorrectionMode;
- }
-
public void setCorrectionMode(int mode) {
mCorrectionMode = mode;
}
diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java
index 8c49ba0cf..10f5ec9db 100644
--- a/java/src/com/android/inputmethod/latin/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java
@@ -672,34 +672,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
mPreviewPopup.dismiss();
}
- private void showPreview(View view, CharSequence word) {
- if (TextUtils.isEmpty(word))
- return;
-
- final TextView previewText = mPreviewText;
- previewText.setTextColor(mParams.mColorTypedWord);
- previewText.setText(word);
- previewText.measure(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- final int[] offsetInWindow = new int[2];
- view.getLocationInWindow(offsetInWindow);
- final int posX = offsetInWindow[0];
- final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
- final PopupWindow previewPopup = mPreviewPopup;
- if (previewPopup.isShowing()) {
- previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
- } else {
- previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
- }
- previewText.setVisibility(VISIBLE);
- mHandler.postHidePreview();
- }
-
private void addToDictionary(CharSequence word) {
- if (mListener.addWordToDictionary(word.toString())) {
- final CharSequence message = getContext().getString(R.string.added_word, word);
- showPreview(mParams.mWordToSaveView, message);
- }
+ mListener.addWordToDictionary(word.toString());
}
private final KeyboardActionListener mMoreSuggestionsListener =
diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java
index 3e53bb0a3..8c28324d8 100644
--- a/java/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserDictionary.java
@@ -20,6 +20,7 @@ import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
@@ -38,11 +39,9 @@ public class UserDictionary extends ExpandableDictionary {
Words.FREQUENCY,
};
- private static final String[] PROJECTION_ADD = {
- Words._ID,
- Words.FREQUENCY,
- Words.LOCALE,
- };
+ // This is not exported by the framework so we pretty much have to write it here verbatim
+ private static final String ACTION_USER_DICTIONARY_INSERT =
+ "com.android.settings.USER_DICTIONARY_INSERT";
private ContentObserver mObserver;
final private String mLocale;
@@ -164,54 +163,19 @@ public class UserDictionary extends ExpandableDictionary {
public synchronized void addWord(final String word, final int frequency) {
// Force load the dictionary here synchronously
if (getRequiresReload()) loadDictionaryAsync();
+ // TODO: do something for the UI. With the following, any sufficiently long word will
+ // look like it will go to the user dictionary but it won't.
// Safeguard against adding long words. Can cause stack overflow.
if (word.length() >= getMaxWordLength()) return;
super.addWord(word, frequency);
- // Update the user dictionary provider
- final ContentValues values = new ContentValues(5);
- values.put(Words.WORD, word);
- values.put(Words.FREQUENCY, frequency);
- values.put(Words.LOCALE, mLocale);
- values.put(Words.APP_ID, 0);
-
- final ContentResolver contentResolver = getContext().getContentResolver();
- final ContentProviderClient client =
- contentResolver.acquireContentProviderClient(Words.CONTENT_URI);
- if (null == client) return;
- new Thread("addWord") {
- @Override
- public void run() {
- Cursor cursor = null;
- try {
- cursor = client.query(Words.CONTENT_URI, PROJECTION_ADD,
- "word=? and ((locale IS NULL) or (locale=?))",
- new String[] { word, mLocale }, null);
- if (cursor != null && cursor.moveToFirst()) {
- final String locale = cursor.getString(cursor.getColumnIndex(Words.LOCALE));
- // If locale is null, we will not override the entry.
- if (locale != null && locale.equals(mLocale.toString())) {
- final long id = cursor.getLong(cursor.getColumnIndex(Words._ID));
- final Uri uri =
- Uri.withAppendedPath(Words.CONTENT_URI, Long.toString(id));
- // Update the entry with new frequency value.
- client.update(uri, values, null, null);
- }
- } else {
- // Insert new entry.
- client.insert(Words.CONTENT_URI, values);
- }
- } catch (RemoteException e) {
- // If we come here, the activity is already about to be killed, and we
- // have no means of contacting the content provider any more.
- // See ContentResolver#insert, inside the catch(){}
- } finally {
- if (null != cursor) cursor.close();
- client.release();
- }
- }
- }.start();
+ // TODO: Add an argument to the intent to specify the frequency.
+ Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT);
+ intent.putExtra(Words.WORD, word);
+ intent.putExtra(Words.LOCALE, mLocale);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
// In case the above does a synchronous callback of the change observer
setRequiresReload(false);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index a89ef001e..8b6ecbef9 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -99,6 +99,25 @@ public class AndroidSpellCheckerService extends SpellCheckerService
private final HashSet<WeakReference<DictionaryCollection>> mDictionaryCollectionsList =
new HashSet<WeakReference<DictionaryCollection>>();
+ public static final int SCRIPT_LATIN = 0;
+ public static final int SCRIPT_CYRILLIC = 1;
+ private static final TreeMap<String, Integer> mLanguageToScript;
+ static {
+ // List of the supported languages and their associated script. We won't check
+ // words written in another script than the selected script, because we know we
+ // don't have those in our dictionary so we will underline everything and we
+ // will never have any suggestions, so it makes no sense checking them.
+ mLanguageToScript = new TreeMap<String, Integer>();
+ mLanguageToScript.put("en", SCRIPT_LATIN);
+ mLanguageToScript.put("fr", SCRIPT_LATIN);
+ mLanguageToScript.put("de", SCRIPT_LATIN);
+ mLanguageToScript.put("nl", SCRIPT_LATIN);
+ mLanguageToScript.put("cs", SCRIPT_LATIN);
+ mLanguageToScript.put("es", SCRIPT_LATIN);
+ mLanguageToScript.put("it", SCRIPT_LATIN);
+ mLanguageToScript.put("ru", SCRIPT_CYRILLIC);
+ }
+
@Override public void onCreate() {
super.onCreate();
mSuggestionThreshold =
@@ -110,6 +129,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService
onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
}
+ private static int getScriptFromLocale(final Locale locale) {
+ final Integer script = mLanguageToScript.get(locale.getLanguage());
+ if (null == script) {
+ throw new RuntimeException("We have been called with an unsupported language: \""
+ + locale.getLanguage() + "\". Framework bug?");
+ }
+ return script;
+ }
+
@Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
if (!PREF_USE_CONTACTS_KEY.equals(key)) return;
@@ -363,7 +391,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService
}
public DictAndProximity createDictAndProximity(final Locale locale) {
- final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo();
+ final int script = getScriptFromLocale(locale);
+ final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo(
+ SpellCheckerProximityInfo.getProximityForScript(script));
final Resources resources = getResources();
final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources);
final DictionaryCollection dictionaryCollection =
@@ -415,25 +445,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService
}
private static class AndroidSpellCheckerSession extends Session {
- private static final int SCRIPT_LATIN = 0;
- private static final int SCRIPT_CYRILLIC = 1;
- private static final TreeMap<String, Integer> mLanguageToScript;
- static {
- // List of the supported languages and their associated script. We won't check
- // words written in another script than the selected script, because we know we
- // don't have those in our dictionary so we will underline everything and we
- // will never have any suggestions, so it makes no sense checking them.
- mLanguageToScript = new TreeMap<String, Integer>();
- mLanguageToScript.put("en", SCRIPT_LATIN);
- mLanguageToScript.put("fr", SCRIPT_LATIN);
- mLanguageToScript.put("de", SCRIPT_LATIN);
- mLanguageToScript.put("nl", SCRIPT_LATIN);
- mLanguageToScript.put("cs", SCRIPT_LATIN);
- mLanguageToScript.put("es", SCRIPT_LATIN);
- mLanguageToScript.put("it", SCRIPT_LATIN);
- mLanguageToScript.put("ru", SCRIPT_CYRILLIC);
- }
-
// Immutable, but need the locale which is not available in the constructor yet
private DictionaryPool mDictionaryPool;
// Likewise
@@ -452,12 +463,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService
final String localeString = getLocale();
mDictionaryPool = mService.getDictionaryPool(localeString);
mLocale = LocaleUtils.constructLocaleFromString(localeString);
- final Integer script = mLanguageToScript.get(mLocale.getLanguage());
- if (null == script) {
- throw new RuntimeException("We have been called with an unsupported language: \""
- + mLocale.getLanguage() + "\". Framework bug?");
- }
- mScript = script;
+ mScript = getScriptFromLocale(mLocale);
}
/*
@@ -565,12 +571,17 @@ public class AndroidSpellCheckerService extends SpellCheckerService
final int length = text.length();
for (int i = 0; i < length; ++i) {
final int character = text.codePointAt(i);
- final int proximityIndex = SpellCheckerProximityInfo.getIndexOf(character);
+ final int proximityIndex =
+ SpellCheckerProximityInfo.getIndexOfCodeForScript(character, mScript);
final int[] proximities;
if (-1 == proximityIndex) {
proximities = new int[] { character };
} else {
- proximities = Arrays.copyOfRange(SpellCheckerProximityInfo.PROXIMITY,
+ // TODO: an initial examination seems to reveal this is actually used
+ // read-only. It should be possible to compute the arrays statically once
+ // and skip doing a copy each time here.
+ proximities = Arrays.copyOfRange(
+ SpellCheckerProximityInfo.getProximityForScript(mScript),
proximityIndex,
proximityIndex + SpellCheckerProximityInfo.ROW_SIZE);
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
index d5b04b27c..9a2bebfdf 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
@@ -29,65 +29,150 @@ public class SpellCheckerProximityInfo {
// as the size of the passed array afterwards so they can't be different.
final public static int ROW_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE;
- // This is a map from the code point to the index in the PROXIMITY array.
- // At the time the native code to read the binary dictionary needs the proximity info be passed
- // as a flat array spaced by MAX_PROXIMITY_CHARS_SIZE columns, one for each input character.
- // Since we need to build such an array, we want to be able to search in our big proximity data
- // quickly by character, and a map is probably the best way to do this.
- final private static TreeMap<Integer, Integer> INDICES = new TreeMap<Integer, Integer>();
+ // Helper methods
+ final protected static void buildProximityIndices(final int[] proximity,
+ final TreeMap<Integer, Integer> indices) {
+ for (int i = 0; i < proximity.length; i += ROW_SIZE) {
+ if (NUL != proximity[i]) indices.put(proximity[i], i);
+ }
+ }
+ final protected static int computeIndex(final int characterCode,
+ final TreeMap<Integer, Integer> indices) {
+ final Integer result = indices.get(characterCode);
+ if (null == result) return -1;
+ return result;
+ }
- // The proximity here is the union of
- // - the proximity for a QWERTY keyboard.
- // - the proximity for an AZERTY keyboard.
- // - the proximity for a QWERTZ keyboard.
- // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other.
- //
- // The reasoning behind this construction is, almost any alphabetic text we may want
- // to spell check has been entered with one of the keyboards above. Also, specifically
- // to English, many spelling errors consist of the last vowel of the word being wrong
- // because in English vowels tend to merge with each other in pronunciation.
- final public static int[] PROXIMITY = {
- 'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
- 'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL,
- 'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ static class Latin {
+ // This is a map from the code point to the index in the PROXIMITY array.
+ // At the time the native code to read the binary dictionary needs the proximity info be
+ // passed as a flat array spaced by MAX_PROXIMITY_CHARS_SIZE columns, one for each input
+ // character.
+ // Since we need to build such an array, we want to be able to search in our big proximity
+ // data quickly by character, and a map is probably the best way to do this.
+ final private static TreeMap<Integer, Integer> INDICES = new TreeMap<Integer, Integer>();
- 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
- 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL,
- 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ // The proximity here is the union of
+ // - the proximity for a QWERTY keyboard.
+ // - the proximity for an AZERTY keyboard.
+ // - the proximity for a QWERTZ keyboard.
+ // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other.
+ //
+ // The reasoning behind this construction is, almost any alphabetic text we may want
+ // to spell check has been entered with one of the keyboards above. Also, specifically
+ // to English, many spelling errors consist of the last vowel of the word being wrong
+ // because in English vowels tend to merge with each other in pronunciation.
+ final private static int[] PROXIMITY = {
+ 'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
+ 'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL,
+ 'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL,
- 'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- };
- static {
- for (int i = 0; i < PROXIMITY.length; i += ROW_SIZE) {
- if (NUL != PROXIMITY[i]) INDICES.put(PROXIMITY[i], i);
+ 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
+ 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL,
+ 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL,
+ 'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ };
+ static {
+ buildProximityIndices(PROXIMITY, INDICES);
+ }
+ private static int getIndexOf(int characterCode) {
+ return computeIndex(characterCode, INDICES);
}
}
- public static int getIndexOf(int characterCode) {
- final Integer result = INDICES.get(characterCode);
- if (null == result) return -1;
- return result;
+
+ static class Cyrillic {
+ final private static TreeMap<Integer, Integer> INDICES = new TreeMap<Integer, Integer>();
+ final private static int[] PROXIMITY = {
+ // TODO: This table is solely based on the keyboard layout. Consult with Russian
+ // speakers on commonly misspelled words/letters.
+ 'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'к', 'у', 'в', 'а', 'п', 'е', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'е', 'к', 'а', 'п', 'р', 'н', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'н', 'е', 'п', 'р', 'о', 'г', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'г', 'н', 'р', 'о', 'л', 'ш', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ш', 'г', 'о', 'л', 'д', 'щ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'щ', 'ш', 'л', 'д', 'ж', 'з', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'а', 'у', 'к', 'е', 'в', 'п', 'ч', 'с', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'п', 'к', 'е', 'н', 'а', 'р', 'с', 'м', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'р', 'е', 'н', 'г', 'п', 'о', 'м', 'и', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'о', 'н', 'г', 'ш', 'р', 'л', 'и', 'т', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'л', 'г', 'ш', 'щ', 'о', 'д', 'т', 'ь', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'д', 'ш', 'щ', 'з', 'л', 'ж', 'ь', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'м', 'а', 'п', 'р', 'с', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'и', 'п', 'р', 'о', 'м', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'т', 'р', 'о', 'л', 'и', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ };
+ static {
+ buildProximityIndices(PROXIMITY, INDICES);
+ }
+ private static int getIndexOf(int characterCode) {
+ return computeIndex(characterCode, INDICES);
+ }
+ }
+
+ public static int[] getProximityForScript(final int script) {
+ switch (script) {
+ case AndroidSpellCheckerService.SCRIPT_LATIN:
+ return Latin.PROXIMITY;
+ case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
+ return Cyrillic.PROXIMITY;
+ default:
+ throw new RuntimeException("Wrong script supplied: " + script);
+ }
+ }
+ public static int getIndexOfCodeForScript(final int characterCode, final int script) {
+ switch (script) {
+ case AndroidSpellCheckerService.SCRIPT_LATIN:
+ return Latin.getIndexOf(characterCode);
+ case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
+ return Cyrillic.getIndexOf(characterCode);
+ default:
+ throw new RuntimeException("Wrong script supplied: " + script);
+ }
}
}