aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java56
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java4
-rw-r--r--java/src/com/android/inputmethod/latin/DicTraverseSession.java6
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java14
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java5
-rw-r--r--java/src/com/android/inputmethod/latin/InputTypeUtils.java7
-rw-r--r--java/src/com/android/inputmethod/latin/LastComposedWord.java9
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java162
-rw-r--r--java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java4
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java13
-rw-r--r--java/src/com/android/inputmethod/latin/SeekBarDialog.java36
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java16
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsFragment.java58
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java68
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java5
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java3
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java20
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java11
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java266
19 files changed, 537 insertions, 226 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 448d25c73..27af3d1e0 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -35,24 +35,16 @@ public final class BinaryDictionary extends Dictionary {
public static final String DICTIONARY_PACK_AUTHORITY =
"com.android.inputmethod.latin.dictionarypack";
- /**
- * There is a difference between what java and native code can handle.
- * This value should only be used in BinaryDictionary.java
- * It is necessary to keep it at this value because some languages e.g. German have
- * really long words.
- */
+ // Must be identical to MAX_WORD_LENGTH in native/jni/src/defines.h
private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH;
- private static final int MAX_WORDS = 18;
- private static final int MAX_SPACES = 16;
-
- private static final int MAX_PREDICTIONS = 60;
- private static final int MAX_RESULTS = Math.max(MAX_PREDICTIONS, MAX_WORDS);
+ // Must be identical to MAX_RESULTS in native/jni/src/defines.h
+ private static final int MAX_RESULTS = 18;
private long mNativeDict;
private final Locale mLocale;
private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS];
- private final int[] mSpaceIndices = new int[MAX_SPACES];
+ private final int[] mSpaceIndices = new int[MAX_RESULTS];
private final int[] mOutputScores = new int[MAX_RESULTS];
private final int[] mOutputTypes = new int[MAX_RESULTS];
@@ -80,16 +72,14 @@ public final class BinaryDictionary extends Dictionary {
/**
* Constructor for the binary dictionary. This is supposed to be called from the
* dictionary factory.
- * @param context the context to access the environment from.
* @param filename the name of the file to read through native code.
* @param offset the offset of the dictionary data within the file.
* @param length the length of the binary data.
* @param useFullEditDistance whether to use the full edit distance in suggestions
* @param dictType the dictionary type, as a human-readable string
*/
- public BinaryDictionary(final Context context, final String filename, final long offset,
- final long length, final boolean useFullEditDistance, final Locale locale,
- final String dictType) {
+ public BinaryDictionary(final String filename, final long offset, final long length,
+ final boolean useFullEditDistance, final Locale locale, final String dictType) {
super(dictType);
mLocale = locale;
mUseFullEditDistance = useFullEditDistance;
@@ -100,24 +90,22 @@ public final class BinaryDictionary extends Dictionary {
JniUtils.loadNativeLibrary();
}
- private native long openNative(String sourceDir, long dictOffset, long dictSize,
- int maxWordLength, int maxWords, int maxPredictions);
- private native void closeNative(long dict);
- private native int getFrequencyNative(long dict, int[] word);
- private native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
- private native int getSuggestionsNative(long dict, long proximityInfo, long traverseSession,
- int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds,
- int[] inputCodePoints, int codesSize, int commitPoint, boolean isGesture,
- int[] prevWordCodePointArray, boolean useFullEditDistance, int[] outputCodePoints,
- int[] outputScores, int[] outputIndices, int[] outputTypes);
+ private static native long openNative(String sourceDir, long dictOffset, long dictSize);
+ private static native void closeNative(long dict);
+ private static native int getFrequencyNative(long dict, int[] word);
+ private static native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
+ private static native int getSuggestionsNative(long dict, long proximityInfo,
+ long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
+ int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
+ boolean isGesture, int[] prevWordCodePointArray, boolean useFullEditDistance,
+ int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes);
private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
private static native int editDistanceNative(int[] before, int[] after);
// TODO: Move native dict into session
private final void loadDictionary(final String path, final long startOffset,
final long length) {
- mNativeDict = openNative(path, startOffset, length, MAX_WORD_LENGTH, MAX_WORDS,
- MAX_PREDICTIONS);
+ mNativeDict = openNative(path, startOffset, length);
}
@Override
@@ -146,16 +134,14 @@ public final class BinaryDictionary extends Dictionary {
}
final InputPointers ips = composer.getInputPointers();
- final int codesSize = isGesture ? ips.getPointerSize() : composerSize;
+ final int inputSize = isGesture ? ips.getPointerSize() : composerSize;
// proximityInfo and/or prevWordForBigrams may not be null.
- final int tmpCount = getSuggestionsNative(mNativeDict,
- proximityInfo.getNativeProximityInfo(), getTraverseSession(sessionId).getSession(),
- ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(),
- mInputCodePoints, codesSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
+ final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
+ getTraverseSession(sessionId).getSession(), ips.getXCoordinates(),
+ ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
+ inputSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
mUseFullEditDistance, mOutputCodePoints, mOutputScores, mSpaceIndices,
mOutputTypes);
- final int count = Math.min(tmpCount, MAX_PREDICTIONS);
-
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
for (int j = 0; j < count; ++j) {
if (composerSize > 0 && mOutputScores[j] < 1) break;
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 3a7772452..483504cfb 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -127,6 +127,7 @@ public final class Constants {
}
public static final class Dictionary {
+ // Must be identical to MAX_WORD_LENGTH in native/jni/src/defines.h
public static final int MAX_WORD_LENGTH = 48;
private Dictionary() {
@@ -183,8 +184,9 @@ public final class Constants {
public static final int CODE_ACTION_PREVIOUS = -9;
public static final int CODE_LANGUAGE_SWITCH = -10;
public static final int CODE_RESEARCH = -11;
+ public static final int CODE_SHIFT_ENTER = -12;
// Code value representing the code is not specified.
- public static final int CODE_UNSPECIFIED = -12;
+ public static final int CODE_UNSPECIFIED = -13;
public static boolean isLetterCode(final int code) {
return code >= CODE_SPACE;
diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
index ce1b64660..534e2116b 100644
--- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java
+++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
@@ -23,10 +23,10 @@ public final class DicTraverseSession {
JniUtils.loadNativeLibrary();
}
- private native long setDicTraverseSessionNative(String locale);
- private native void initDicTraverseSessionNative(long nativeDicTraverseSession,
+ private static native long setDicTraverseSessionNative(String locale);
+ private static native void initDicTraverseSessionNative(long nativeDicTraverseSession,
long dictionary, int[] previousWord, int previousWordLength);
- private native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
+ private static native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
private long mNativeDicTraverseSession;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index f381973ae..22cf5b38d 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -58,9 +58,8 @@ public final class DictionaryFactory {
BinaryDictionaryGetter.getDictionaryFiles(locale, context);
if (null != assetFileList) {
for (final AssetFileAddress f : assetFileList) {
- final BinaryDictionary binaryDictionary =
- new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength,
- useFullEditDistance, locale, Dictionary.TYPE_MAIN);
+ final BinaryDictionary binaryDictionary = new BinaryDictionary(f.mFilename,
+ f.mOffset, f.mLength, useFullEditDistance, locale, Dictionary.TYPE_MAIN);
if (binaryDictionary.isValidDictionary()) {
dictList.add(binaryDictionary);
}
@@ -112,7 +111,7 @@ public final class DictionaryFactory {
Log.e(TAG, "sourceDir is not a file: " + sourceDir);
return null;
}
- return new BinaryDictionary(context, sourceDir, afd.getStartOffset(), afd.getLength(),
+ return new BinaryDictionary(sourceDir, afd.getStartOffset(), afd.getLength(),
false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
} catch (android.content.res.Resources.NotFoundException e) {
Log.e(TAG, "Could not find the resource");
@@ -130,17 +129,16 @@ public final class DictionaryFactory {
/**
* Create a dictionary from passed data. This is intended for unit tests only.
- * @param context the test context to create this data from.
* @param dictionary the file to read
* @param startOffset the offset in the file where the data starts
* @param length the length of the data
* @param useFullEditDistance whether to use the full edit distance in suggestions
* @return the created dictionary, or null.
*/
- public static Dictionary createDictionaryForTest(Context context, File dictionary,
- long startOffset, long length, final boolean useFullEditDistance, Locale locale) {
+ public static Dictionary createDictionaryForTest(File dictionary, long startOffset, long length,
+ final boolean useFullEditDistance, Locale locale) {
if (dictionary.isFile()) {
- return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length,
+ return new BinaryDictionary(dictionary.getAbsolutePath(), startOffset, length,
useFullEditDistance, locale, Dictionary.TYPE_MAIN);
} else {
Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath());
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 47adaa8ed..2c7fdcc93 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -279,9 +279,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final long length = file.length();
// Build the new binary dictionary
- final BinaryDictionary newBinaryDictionary =
- new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */,
- null, mDictType);
+ final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0, length,
+ true /* useFullEditDistance */, null, mDictType);
if (mBinaryDictionary != null) {
// Ensure all threads accessing the current dictionary have finished before swapping in
diff --git a/java/src/com/android/inputmethod/latin/InputTypeUtils.java b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
index 55414b809..e2eacb3f0 100644
--- a/java/src/com/android/inputmethod/latin/InputTypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
@@ -105,7 +105,7 @@ public final class InputTypeUtils implements InputType {
return true;
}
- public static int getActionIdFromEditorInfo(final EditorInfo editorInfo) {
+ public static int getImeOptionsActionIdFromEditorInfo(final EditorInfo editorInfo) {
final int actionId = editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
if ((editorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
return EditorInfo.IME_ACTION_NONE;
@@ -115,4 +115,9 @@ public final class InputTypeUtils implements InputType {
return actionId;
}
}
+
+ public static int getConcreteActionIdFromEditorInfo(final EditorInfo editorInfo) {
+ final int actionId = getImeOptionsActionIdFromEditorInfo(editorInfo);
+ return actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL ? editorInfo.actionId : actionId;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java
index 488a6fcf2..a4019e906 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -45,19 +45,21 @@ public final class LastComposedWord {
public final String mCommittedWord;
public final String mSeparatorString;
public final String mPrevWord;
+ public final int mCapitalizedMode;
public final InputPointers mInputPointers =
new InputPointers(Constants.Dictionary.MAX_WORD_LENGTH);
private boolean mActive;
public static final LastComposedWord NOT_A_COMPOSED_WORD =
- new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null);
+ new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null,
+ WordComposer.CAPS_MODE_OFF);
// Warning: this is using the passed objects as is and fully expects them to be
// immutable. Do not fiddle with their contents after you passed them to this constructor.
public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers,
- final String typedWord, final String committedWord,
- final String separatorString, final String prevWord) {
+ final String typedWord, final String committedWord, final String separatorString,
+ final String prevWord, final int capitalizedMode) {
mPrimaryKeyCodes = primaryKeyCodes;
if (inputPointers != null) {
mInputPointers.copy(inputPointers);
@@ -67,6 +69,7 @@ public final class LastComposedWord {
mSeparatorString = separatorString;
mActive = true;
mPrevWord = prevWord;
+ mCapitalizedMode = capitalizedMode;
}
public void deactivate() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 152118d98..d02c4df7e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -166,6 +166,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean mExpectingUpdateSelection;
private int mDeleteCount;
private long mLastKeyTime;
+ private int mActionId;
// Member variables for remembering the current device orientation.
private int mDisplayOrientation;
@@ -754,6 +755,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mLastSelectionStart = editorInfo.initialSelStart;
mLastSelectionEnd = editorInfo.initialSelEnd;
+ mActionId = InputTypeUtils.getConcreteActionIdFromEditorInfo(editorInfo);
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
@@ -1223,7 +1225,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mPositionalInfoForUserDictPendingAddition =
new PositionalInfoForUserDictPendingAddition(
- word, mLastSelectionEnd, getCurrentInputEditorInfo());
+ word, mLastSelectionEnd, getCurrentInputEditorInfo(),
+ mLastComposedWord.mCapitalizedMode);
mUserDictionary.addWordToUserDictionary(word, 128);
}
@@ -1272,10 +1275,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return mOptionsDialog != null && mOptionsDialog.isShowing();
}
- private static int getActionId(final Keyboard keyboard) {
- return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE;
- }
-
private void performEditorAction(final int actionId) {
mConnection.performEditorAction(actionId);
}
@@ -1301,13 +1300,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
private void sendKeyCodePoint(final int code) {
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_sendKeyCodePoint(code);
+ }
// TODO: Remove this special handling of digit letters.
// For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}.
if (code >= '0' && code <= '9') {
sendDownUpKeyEventForBackwardCompatibility(code - '0' + KeyEvent.KEYCODE_0);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_sendKeyCodePoint(code);
- }
return;
}
@@ -1327,6 +1326,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Implementation of {@link KeyboardActionListener}.
@Override
public void onCodeInput(final int primaryCode, final int x, final int y) {
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
+ }
final long when = SystemClock.uptimeMillis();
if (primaryCode != Constants.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
mDeleteCount = 0;
@@ -1366,9 +1368,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
case Constants.CODE_SHORTCUT:
mSubtypeSwitcher.switchToShortcutIME(this);
break;
- case Constants.CODE_ACTION_ENTER:
- performEditorAction(getActionId(switcher.getKeyboard()));
- break;
case Constants.CODE_ACTION_NEXT:
performEditorAction(EditorInfo.IME_ACTION_NEXT);
break;
@@ -1383,32 +1382,19 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
ResearchLogger.getInstance().onResearchKeySelected(this);
}
break;
- default:
- mSpaceState = SPACE_STATE_NONE;
- if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
- didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
- } else {
- if (SPACE_STATE_PHANTOM == spaceState) {
- if (ProductionFlag.IS_INTERNAL) {
- if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
- Stats.onAutoCorrection(
- "", mWordComposer.getTypedWord(), " ", mWordComposer);
- }
- }
- commitTyped(LastComposedWord.NOT_A_SEPARATOR);
- }
- final int keyX, keyY;
- final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
- if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
- keyX = x;
- keyY = y;
- } else {
- keyX = Constants.NOT_A_COORDINATE;
- keyY = Constants.NOT_A_COORDINATE;
- }
- handleCharacter(primaryCode, keyX, keyY, spaceState);
+ case Constants.CODE_ACTION_ENTER:
+ if (EditorInfo.IME_ACTION_NONE != mActionId
+ && EditorInfo.IME_ACTION_UNSPECIFIED != mActionId) {
+ performEditorAction(mActionId);
+ break;
}
- mExpectingUpdateSelection = true;
+ didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
+ break;
+ case Constants.CODE_SHIFT_ENTER:
+ didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
+ break;
+ default:
+ didAutoCorrect = handleNonSpecialCharacter(primaryCode, x, y, spaceState);
break;
}
switcher.onCodeInput(primaryCode);
@@ -1420,9 +1406,38 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mEnteredText = null;
}
mConnection.endBatchEdit();
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
+ }
+
+ private boolean handleNonSpecialCharacter(final int primaryCode, final int x, final int y,
+ final int spaceState) {
+ mSpaceState = SPACE_STATE_NONE;
+ final boolean didAutoCorrect;
+ if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
+ didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
+ } else {
+ didAutoCorrect = false;
+ if (SPACE_STATE_PHANTOM == spaceState) {
+ if (ProductionFlag.IS_INTERNAL) {
+ if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
+ Stats.onAutoCorrection(
+ "", mWordComposer.getTypedWord(), " ", mWordComposer);
+ }
+ }
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ }
+ final int keyX, keyY;
+ final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
+ if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
+ keyX = x;
+ keyY = y;
+ } else {
+ keyX = Constants.NOT_A_COORDINATE;
+ keyY = Constants.NOT_A_COORDINATE;
+ }
+ handleCharacter(primaryCode, keyX, keyY, spaceState);
}
+ mExpectingUpdateSelection = true;
+ return didAutoCorrect;
}
// Called from PointerTracker through the KeyboardActionListener interface
@@ -1479,12 +1494,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mSpaceState = SPACE_STATE_PHANTOM;
} else {
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
- // TODO: reverse this logic. We should have the means to determine whether a character
- // should usually be followed by a space, and it should be more readable.
- if (Constants.NOT_A_CODE != codePointBeforeCursor
- && !Character.isWhitespace(codePointBeforeCursor)
- && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(codePointBeforeCursor)
- && !mSettings.getCurrent().isWeakSpaceStripper(codePointBeforeCursor)) {
+ if (mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) {
mSpaceState = SPACE_STATE_PHANTOM;
}
}
@@ -1667,7 +1677,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mWordComposer.isBatchMode()) {
if (ProductionFlag.IS_EXPERIMENTAL) {
final String word = mWordComposer.getTypedWord();
- ResearchLogger.latinIME_handleBackspace_batch(word);
+ ResearchLogger.latinIME_handleBackspace_batch(word, 1);
ResearchLogger.getInstance().uncommitCurrentLogUnit(
word, false /* dumpCurrentLogUnit */);
}
@@ -1718,14 +1728,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// We should backspace one char and restart suggestion if at the end of a word.
if (mLastSelectionStart != mLastSelectionEnd) {
// If there is a selection, remove it.
- final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart;
+ final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart;
mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd);
// Reset mLastSelectionEnd to mLastSelectionStart. This is what is supposed to
// happen, and if it's wrong, the next call to onUpdateSelection will correct it,
// but we want to set it right away to avoid it being used with the wrong values
// later (typically, in a subsequent press on backspace).
mLastSelectionEnd = mLastSelectionStart;
- mConnection.deleteSurroundingText(lengthToDelete, 0);
+ mConnection.deleteSurroundingText(numCharsDeleted, 0);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_handleBackspace(numCharsDeleted);
+ }
} else {
// There is no selection, just delete one character.
if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) {
@@ -1742,8 +1755,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
} else {
mConnection.deleteSurroundingText(1, 0);
}
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_handleBackspace(1);
+ }
if (mDeleteCount > DELETE_ACCELERATE_AT) {
mConnection.deleteSurroundingText(1, 0);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_handleBackspace(1);
+ }
}
}
if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
@@ -1752,25 +1771,22 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
+ /*
+ * Strip a trailing space if necessary and returns whether it's a swap weak space situation.
+ */
private boolean maybeStripSpace(final int code,
final int spaceState, final boolean isFromSuggestionStrip) {
if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
mConnection.removeTrailingSpace();
return false;
- } else if ((SPACE_STATE_WEAK == spaceState
- || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
+ }
+ if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
&& isFromSuggestionStrip) {
- if (mSettings.getCurrent().isWeakSpaceSwapper(code)) {
- return true;
- } else {
- if (mSettings.getCurrent().isWeakSpaceStripper(code)) {
- mConnection.removeTrailingSpace();
- }
- return false;
- }
- } else {
- return false;
+ if (mSettings.getCurrent().isUsuallyPrecededBySpace(code)) return false;
+ if (mSettings.getCurrent().isUsuallyFollowedBySpace(code)) return true;
+ mConnection.removeTrailingSpace();
}
+ return false;
}
private void handleCharacter(final int primaryCode, final int x,
@@ -1778,7 +1794,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
boolean isComposingWord = mWordComposer.isComposingWord();
if (SPACE_STATE_PHANTOM == spaceState &&
- !mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) {
+ !mSettings.getCurrent().isWordConnector(primaryCode)) {
if (isComposingWord) {
// Sanity check
throw new RuntimeException("Should not be composing here");
@@ -1790,7 +1806,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
// thread here.
if (!isComposingWord && (isAlphabet(primaryCode)
- || mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode))
+ || mSettings.getCurrent().isWordConnector(primaryCode))
&& mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
// Reset entirely the composing state anyway, then start composing a new word unless
@@ -1844,7 +1860,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean handleSeparator(final int primaryCode, final int x, final int y,
final int spaceState) {
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_handleSeparator();
+ ResearchLogger.recordTimeForLogUnitSplit();
}
boolean didAutoCorrect = false;
// Handle separator
@@ -1862,7 +1878,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Constants.SUGGESTION_STRIP_COORDINATE == x);
if (SPACE_STATE_PHANTOM == spaceState &&
- mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
+ mSettings.getCurrent().isUsuallyPrecededBySpace(primaryCode)) {
promotePhantomSpace();
}
sendKeyCodePoint(primaryCode);
@@ -1877,16 +1893,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mHandler.startDoubleSpacePeriodTimer();
- if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
- mHandler.postUpdateSuggestionStrip();
- }
+ mHandler.postUpdateSuggestionStrip();
} else {
if (swapWeakSpace) {
swapSwapperAndSpace();
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
} else if (SPACE_STATE_PHANTOM == spaceState
- && !mSettings.getCurrent().isWeakSpaceStripper(primaryCode)
- && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
+ && mSettings.getCurrent().isUsuallyFollowedBySpace(primaryCode)) {
// If we are in phantom space state, and the user presses a separator, we want to
// stay in phantom space state so that the next keypress has a chance to add the
// space. For example, if I type "Good dat", pick "day" from the suggestion strip
@@ -2125,7 +2138,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_punctuationSuggestion(index, suggestion,
- false /* isBatchMode */);
+ false /* isBatchMode */, suggestedWords.mIsPrediction);
}
return;
}
@@ -2135,9 +2148,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// In the batch input mode, a manually picked suggested word should just replace
// the current batch input text and there is no need for a phantom space.
&& !mWordComposer.isBatchMode()) {
- int firstChar = Character.codePointAt(suggestion, 0);
- if ((!mSettings.getCurrent().isWeakSpaceStripper(firstChar))
- && (!mSettings.getCurrent().isWeakSpaceSwapper(firstChar))) {
+ final int firstChar = Character.codePointAt(suggestion, 0);
+ if (!mSettings.getCurrent().isWordSeparator(firstChar)
+ || mSettings.getCurrent().isUsuallyPrecededBySpace(firstChar)) {
promotePhantomSpace();
}
}
@@ -2312,7 +2325,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord,
- mWordComposer.isBatchMode());
+ mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString);
ResearchLogger.getInstance().uncommitCurrentLogUnit(committedWord,
true /* dumpCurrentLogUnit */);
}
@@ -2327,6 +2340,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
public void promotePhantomSpace() {
if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) {
sendKeyCodePoint(Constants.CODE_SPACE);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_promotePhantomSpace();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
index 1fd25636c..a33cefcd6 100644
--- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
+++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
@@ -33,13 +33,15 @@ public final class PositionalInfoForUserDictPendingAddition {
final private String mOriginalWord;
final private int mCursorPos; // Position of the cursor after the word
final private EditorInfo mEditorInfo; // On what binding this has been added
+ final private int mCapitalizedMode;
private String mActualWordBeingAdded;
public PositionalInfoForUserDictPendingAddition(final String word, final int cursorPos,
- final EditorInfo editorInfo) {
+ final EditorInfo editorInfo, final int capitalizedMode) {
mOriginalWord = word;
mCursorPos = cursorPos;
mEditorInfo = editorInfo;
+ mCapitalizedMode = capitalizedMode;
}
public void setActualWordBeingAdded(final String actualWordBeingAdded) {
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index f7268fc33..0e75533f5 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -577,11 +577,11 @@ public final class RichInputConnection {
final CharSequence before = getTextBeforeCursor(1, 0);
final CharSequence after = getTextAfterCursor(1, 0);
if (!TextUtils.isEmpty(before) && !settingsValues.isWordSeparator(before.charAt(0))
- && !settingsValues.isSymbolExcludedFromWordSeparators(before.charAt(0))) {
+ && !settingsValues.isWordConnector(before.charAt(0))) {
return true;
}
if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0))
- && !settingsValues.isSymbolExcludedFromWordSeparators(after.charAt(0))) {
+ && !settingsValues.isWordConnector(after.charAt(0))) {
return true;
}
return false;
@@ -633,12 +633,9 @@ public final class RichInputConnection {
final char firstChar = word.charAt(0); // we just tested that word is not empty
if (word.length() == 1 && !Character.isLetter(firstChar)) return null;
- // We only suggest on words that start with a letter or a symbol that is excluded from
- // word separators (see #handleCharacterWhileInBatchEdit).
- if (!(Character.isLetter(firstChar)
- || settings.isSymbolExcludedFromWordSeparators(firstChar))) {
- return null;
- }
+ // We don't restart suggestion if the first character is not a letter, because we don't
+ // start composing when the first character is not a letter.
+ if (!Character.isLetter(firstChar)) return null;
return word;
}
diff --git a/java/src/com/android/inputmethod/latin/SeekBarDialog.java b/java/src/com/android/inputmethod/latin/SeekBarDialog.java
index e576c0984..c736d1b1a 100644
--- a/java/src/com/android/inputmethod/latin/SeekBarDialog.java
+++ b/java/src/com/android/inputmethod/latin/SeekBarDialog.java
@@ -30,6 +30,8 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
public interface Listener {
public void onPositiveButtonClick(final SeekBarDialog dialog);
public void onNegativeButtonClick(final SeekBarDialog dialog);
+ public void onNeutralButtonClick(final SeekBarDialog dialog);
+ public void onDismiss(final SeekBarDialog dialog);
public void onProgressChanged(final SeekBarDialog dialog);
public void onStartTrackingTouch(final SeekBarDialog dialog);
public void onStopTrackingTouch(final SeekBarDialog dialog);
@@ -39,7 +41,11 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
@Override
public void onPositiveButtonClick(final SeekBarDialog dialog) {}
@Override
- public void onNegativeButtonClick(final SeekBarDialog dialog) { dialog.dismiss(); }
+ public void onNegativeButtonClick(final SeekBarDialog dialog) {}
+ @Override
+ public void onNeutralButtonClick(final SeekBarDialog dialog) {}
+ @Override
+ public void onDismiss(final SeekBarDialog dialog) {}
@Override
public void onProgressChanged(final SeekBarDialog dialog) {}
@Override
@@ -63,6 +69,9 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
dialogBuilder.setView(builder.mView);
dialogBuilder.setPositiveButton(android.R.string.ok, this);
dialogBuilder.setNegativeButton(android.R.string.cancel, this);
+ if (builder.mNeutralButtonTextResId != 0) {
+ dialogBuilder.setNeutralButton(builder.mNeutralButtonTextResId, this);
+ }
mDialog = dialogBuilder.create();
mListener = (builder.mListener == null) ? EMPTY_ADAPTER : builder.mListener;
mValueView = (TextView)builder.mView.findViewById(R.id.seek_bar_dialog_value);
@@ -101,15 +110,21 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
}
@Override
- public void onClick(final DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
+ public void onClick(final DialogInterface dialog, final int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
mListener.onPositiveButtonClick(this);
- return;
- }
- if (which == DialogInterface.BUTTON_NEGATIVE) {
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
mListener.onNegativeButtonClick(this);
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ mListener.onNeutralButtonClick(this);
+ break;
+ default:
return;
}
+ mListener.onDismiss(this);
}
@Override
@@ -135,6 +150,7 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
final AlertDialog.Builder mDialogBuilder;
final View mView;
+ int mNeutralButtonTextResId;
int mMaxValue;
int mValueFormatResId;
int mValue;
@@ -150,8 +166,14 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
return this;
}
+ public Builder setNeutralButtonText(final int resId) {
+ mNeutralButtonTextResId = resId;
+ return this;
+ }
+
public Builder setMaxValue(final int max) {
mMaxValue = max;
+ mValue = Math.min(mValue, max);
return this;
}
@@ -161,7 +183,7 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
}
public Builder setValue(final int value) {
- mValue = value;
+ mValue = Math.min(value, mMaxValue);
return this;
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index c5930a935..866bef0f2 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -167,19 +167,21 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static float readKeypressSoundVolume(final SharedPreferences prefs,
final Resources res) {
final float volume = prefs.getFloat(PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
- if (volume >= 0) {
- return volume;
- }
+ return (volume >= 0) ? volume : readDefaultKeypressSoundVolume(res);
+ }
+
+ public static float readDefaultKeypressSoundVolume(final Resources res) {
return Float.parseFloat(
ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes));
}
- public static int readVibrationDuration(final SharedPreferences prefs,
+ public static int readKeypressVibrationDuration(final SharedPreferences prefs,
final Resources res) {
final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1);
- if (ms >= 0) {
- return ms;
- }
+ return (ms >= 0) ? ms : readDefaultKeypressVibrationDuration(res);
+ }
+
+ public static int readDefaultKeypressVibrationDuration(final Resources res) {
return Integer.parseInt(
ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations));
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
index 507a37b7c..6a4371835 100644
--- a/java/src/com/android/inputmethod/latin/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -180,7 +180,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment
});
mKeypressVibrationDurationSettingsPref.setSummary(
res.getString(R.string.settings_keypress_vibration_duration,
- Settings.readVibrationDuration(prefs, res)));
+ Settings.readKeypressVibrationDuration(prefs, res)));
}
mKeypressSoundVolumeSettingsPref =
@@ -308,10 +308,29 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final Context context = getActivity();
final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref;
final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ private void writePreference(final SharedPreferences sp, final int value) {
+ sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, value).apply();
+ }
+
+ private void feedbackSettingsValue(final int value) {
+ AudioAndHapticFeedbackManager.getInstance().vibrate(value);
+ }
+
@Override
public void onPositiveButtonClick(final SeekBarDialog dialog) {
- final int ms = dialog.getValue();
- sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
+ writePreference(sp, dialog.getValue());
+ }
+
+ @Override
+ public void onNeutralButtonClick(final SeekBarDialog dialog) {
+ final int defaultValue =
+ Settings.readDefaultKeypressVibrationDuration(context.getResources());
+ dialog.setValue(defaultValue, false /* fromUser */);
+ writePreference(sp, defaultValue);
+ }
+
+ @Override
+ public void onDismiss(final SeekBarDialog dialog) {
if (settingsPref != null) {
settingsPref.setSummary(dialog.getValueText());
}
@@ -319,13 +338,13 @@ public final class SettingsFragment extends InputMethodSettingsFragment
@Override
public void onStopTrackingTouch(final SeekBarDialog dialog) {
- final int ms = dialog.getValue();
- AudioAndHapticFeedbackManager.getInstance().vibrate(ms);
+ feedbackSettingsValue(dialog.getValue());
}
};
- final int currentMs = Settings.readVibrationDuration(sp, getResources());
+ final int currentMs = Settings.readKeypressVibrationDuration(sp, getResources());
final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
builder.setTitle(R.string.prefs_keypress_vibration_duration_settings)
+ .setNeutralButtonText(R.string.button_default)
.setListener(listener)
.setMaxValue(AudioAndHapticFeedbackManager.MAX_KEYPRESS_VIBRATION_DURATION)
.setValueFromat(R.string.settings_keypress_vibration_duration)
@@ -348,10 +367,29 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
final PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref;
final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ private void writePreference(final SharedPreferences sp, final float value) {
+ sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, value).apply();
+ }
+
+ private void feedbackSettingsValue(final float value) {
+ am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, value);
+ }
+
@Override
public void onPositiveButtonClick(final SeekBarDialog dialog) {
- final float volume = dialog.getValue() / PERCENT_FLOAT;
- sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply();
+ writePreference(sp, dialog.getValue() / PERCENT_FLOAT);
+ }
+
+ @Override
+ public void onNeutralButtonClick(final SeekBarDialog dialog) {
+ final float defaultValue =
+ Settings.readDefaultKeypressSoundVolume(context.getResources());
+ dialog.setValue((int)(defaultValue * PERCENT_INT), false /* fromUser */);
+ writePreference(sp, defaultValue);
+ }
+
+ @Override
+ public void onDismiss(final SeekBarDialog dialog) {
if (settingsPref != null) {
settingsPref.setSummary(dialog.getValueText());
}
@@ -359,13 +397,13 @@ public final class SettingsFragment extends InputMethodSettingsFragment
@Override
public void onStopTrackingTouch(final SeekBarDialog dialog) {
- final float volume = dialog.getValue() / PERCENT_FLOAT;
- am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume);
+ feedbackSettingsValue(dialog.getValue() / PERCENT_FLOAT);
}
};
final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources());
builder.setTitle(R.string.prefs_keypress_sound_volume_settings)
+ .setNeutralButtonText(R.string.button_default)
.setListener(listener)
.setMaxValue(PERCENT_INT)
.setValue(currentVolumeInt)
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 9a2024618..1e3bdf0fd 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -37,11 +37,10 @@ public final class SettingsValues {
// From resources:
public final int mDelayUpdateOldSuggestions;
- public final String mWeakSpaceStrippers;
- public final String mWeakSpaceSwappers;
- private final String mPhantomSpacePromotingSymbols;
+ public final int[] mSymbolsPrecededBySpace;
+ public final int[] mSymbolsFollowedBySpace;
+ public final int[] mWordConnectors;
public final SuggestedWords mSuggestPuncList;
- private final String mSymbolsExcludedFromWordSeparators;
public final String mWordSeparators;
public final CharSequence mHintToSaveText;
@@ -79,25 +78,19 @@ public final class SettingsValues {
final InputAttributes inputAttributes) {
// Get the resources
mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
- mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols);
- mWeakSpaceSwappers = res.getString(R.string.weak_space_swapping_symbols);
- mPhantomSpacePromotingSymbols = res.getString(R.string.phantom_space_promoting_symbols);
- if (LatinImeLogger.sDBG) {
- final int length = mWeakSpaceStrippers.length();
- for (int i = 0; i < length; i = mWeakSpaceStrippers.offsetByCodePoints(i, 1)) {
- if (isWeakSpaceSwapper(mWeakSpaceStrippers.codePointAt(i))) {
- throw new RuntimeException("Char code " + mWeakSpaceStrippers.codePointAt(i)
- + " is both a weak space swapper and stripper.");
- }
- }
- }
+ mSymbolsPrecededBySpace =
+ StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space));
+ Arrays.sort(mSymbolsPrecededBySpace);
+ mSymbolsFollowedBySpace =
+ StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space));
+ Arrays.sort(mSymbolsFollowedBySpace);
+ mWordConnectors =
+ StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors));
+ Arrays.sort(mWordConnectors);
final String[] suggestPuncsSpec = KeySpecParser.parseCsvString(
res.getString(R.string.suggested_punctuations), null);
mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
- mSymbolsExcludedFromWordSeparators =
- res.getString(R.string.symbols_excluded_from_word_separators);
- mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers,
- mSymbolsExcludedFromWordSeparators, res);
+ mWordSeparators = res.getString(R.string.symbols_word_separators);
mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
// Store the input attributes
@@ -128,7 +121,7 @@ public final class SettingsValues {
mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res);
// Compute other readable settings
- mKeypressVibrationDuration = Settings.readVibrationDuration(prefs, res);
+ mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res);
mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res);
mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res);
mAutoCorrectionThreshold = readAutoCorrectionThreshold(res,
@@ -169,25 +162,16 @@ public final class SettingsValues {
return mWordSeparators.contains(String.valueOf((char)code));
}
- public boolean isSymbolExcludedFromWordSeparators(final int code) {
- return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
- }
-
- // TODO: use "Phantom" instead of "Weak" in this method name
- public boolean isWeakSpaceStripper(final int code) {
- // TODO: this does not work if the code does not fit in a char
- return mWeakSpaceStrippers.contains(String.valueOf((char)code));
+ public boolean isWordConnector(final int code) {
+ return Arrays.binarySearch(mWordConnectors, code) >= 0;
}
- // TODO: use "Phantom" instead of "Weak" in this method name
- public boolean isWeakSpaceSwapper(final int code) {
- // TODO: this does not work if the code does not fit in a char
- return mWeakSpaceSwappers.contains(String.valueOf((char)code));
+ public boolean isUsuallyPrecededBySpace(final int code) {
+ return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
}
- public boolean isPhantomSpacePromotingSymbol(final int code) {
- // TODO: this does not work if the code does not fit in a char
- return mPhantomSpacePromotingSymbols.contains(String.valueOf((char)code));
+ public boolean isUsuallyFollowedBySpace(final int code) {
+ return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0;
}
public boolean shouldInsertSpacesAutomatically() {
@@ -239,18 +223,6 @@ public final class SettingsValues {
false /* isPrediction */);
}
- private static String createWordSeparators(final String weakSpaceStrippers,
- final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators,
- final Resources res) {
- String wordSeparators = weakSpaceStrippers + weakSpaceSwappers
- + res.getString(R.string.phantom_space_promoting_symbols);
- for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
- wordSeparators = wordSeparators.replace(
- symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
- }
- return wordSeparators;
- }
-
private static final int SUGGESTION_VISIBILITY_SHOW_VALUE =
R.string.prefs_suggestion_visibility_show_value;
private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE =
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 3dc2ba95b..2abf75da4 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -72,9 +72,8 @@ public final class Suggest {
}
@UsedForTesting
- Suggest(final Context context, final File dictionary,
- final long startOffset, final long length, final Locale locale) {
- final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
+ Suggest(final File dictionary, final long startOffset, final long length, final Locale locale) {
+ final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(dictionary,
startOffset, length /* useFullEditDistance */, false, locale);
mLocale = locale;
mMainDictionary = mainDict;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 4f1759079..b9ec4979d 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -350,7 +350,7 @@ public final class WordComposer {
mPrimaryKeyCodes = new int[MAX_WORD_LENGTH];
final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes,
mInputPointers, mTypedWord.toString(), committedWord, separatorString,
- prevWord);
+ prevWord, mCapitalizedMode);
mInputPointers.reset();
if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD
&& type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) {
@@ -374,6 +374,7 @@ public final class WordComposer {
mTypedWord.setLength(0);
mTypedWord.append(lastComposedWord.mTypedWord);
refreshSize();
+ mCapitalizedMode = lastComposedWord.mCapitalizedMode;
mAutoCorrection = null; // This will be filled by the next call to updateSuggestion.
mIsResumed = true;
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 89d6c9010..907c0cdca 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -81,6 +81,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
public static final int SCRIPT_LATIN = 0;
public static final int SCRIPT_CYRILLIC = 1;
+ public static final int SCRIPT_GREEK = 2;
public static final String SINGLE_QUOTE = "\u0027";
public static final String APOSTROPHE = "\u2019";
private static final TreeMap<String, Integer> mLanguageToScript;
@@ -94,18 +95,23 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
// IMPORTANT: this only contains languages - do not write countries in there.
// Only the language is searched from the map.
mLanguageToScript = CollectionUtils.newTreeMap();
- 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("da", SCRIPT_LATIN);
+ mLanguageToScript.put("de", SCRIPT_LATIN);
+ mLanguageToScript.put("el", SCRIPT_GREEK);
+ mLanguageToScript.put("en", SCRIPT_LATIN);
mLanguageToScript.put("es", SCRIPT_LATIN);
- mLanguageToScript.put("it", SCRIPT_LATIN);
+ mLanguageToScript.put("fi", SCRIPT_LATIN);
+ mLanguageToScript.put("fr", SCRIPT_LATIN);
mLanguageToScript.put("hr", SCRIPT_LATIN);
+ mLanguageToScript.put("it", SCRIPT_LATIN);
+ mLanguageToScript.put("lt", SCRIPT_LATIN);
+ mLanguageToScript.put("lv", SCRIPT_LATIN);
+ mLanguageToScript.put("nb", SCRIPT_LATIN);
+ mLanguageToScript.put("nl", SCRIPT_LATIN);
mLanguageToScript.put("pt", SCRIPT_LATIN);
+ mLanguageToScript.put("sl", SCRIPT_LATIN);
mLanguageToScript.put("ru", SCRIPT_CYRILLIC);
- // TODO: Make a persian proximity, and activate the Farsi subtype.
- // mLanguageToScript.put("fa", SCRIPT_PERSIAN);
}
@Override public void onCreate() {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 470943be1..6581978c9 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -143,8 +143,17 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
// All Cyrillic characters are in the 400~52F block. There are some in the upper
// Unicode range, but they are archaic characters that are not used in modern
- // russian and are not used by our dictionary.
+ // Russian and are not used by our dictionary.
return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
+ // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
+ // Our dictionary also contains a few words with 0xF2; it would be best to check
+ // if that's correct, but a Google search does return results for these words so
+ // they are probably okay.
+ return (codePoint >= 0x370 && codePoint <= 0x3FF)
+ || (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
+ || codePoint == 0xF2;
default:
// Should never come here
throw new RuntimeException("Impossible value of script: " + script);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
index 6c0d79c2b..572a826a5 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
@@ -73,6 +73,12 @@ public final class SpellCheckerProximityInfo {
// 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.
+ /*
+ The Qwerty layout this represents looks like the following:
+ q w e r t y u i o p
+ a s d f g h j k l
+ z x c v b n m
+ */
final static int[] PROXIMITY = {
// Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
// and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
@@ -127,10 +133,13 @@ public final class SpellCheckerProximityInfo {
final private static TreeMap<Integer, Integer> INDICES = CollectionUtils.newTreeMap();
// TODO: The following table is solely based on the keyboard layout. Consult with Russian
// speakers on commonly misspelled words/letters.
- final static int[] PROXIMITY = {
- // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
- // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
- // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
+ /*
+ The Russian layout this represents looks like the following:
+ й ц у к е н г ш щ з х
+ ф ы в а п р о л д ж э
+ я ч с м и т ь б ю
+
+ This gives us the following table:
'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
@@ -143,7 +152,6 @@ public final class SpellCheckerProximityInfo {
'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- // Proximity for row 2. See comment above about size.
'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
@@ -156,7 +164,6 @@ public final class SpellCheckerProximityInfo {
'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- // Proximity for row 3. See comment above about size.
'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
@@ -166,6 +173,249 @@ public final class SpellCheckerProximityInfo {
'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ Using the following characters:
+ */
+ private static final int CY_SHORT_I = '\u0439'; // й
+ private static final int CY_TSE = '\u0446'; // ц
+ private static final int CY_U = '\u0443'; // у
+ private static final int CY_KA = '\u043A'; // к
+ private static final int CY_IE = '\u0435'; // е
+ private static final int CY_EN = '\u043D'; // н
+ private static final int CY_GHE = '\u0433'; // г
+ private static final int CY_SHA = '\u0448'; // ш
+ private static final int CY_SHCHA = '\u0449'; // щ
+ private static final int CY_ZE = '\u0437'; // з
+ private static final int CY_HA = '\u0445'; // х
+ private static final int CY_EF = '\u0444'; // ф
+ private static final int CY_YERU = '\u044B'; // ы
+ private static final int CY_VE = '\u0432'; // в
+ private static final int CY_A = '\u0430'; // а
+ private static final int CY_PE = '\u043F'; // п
+ private static final int CY_ER = '\u0440'; // р
+ private static final int CY_O = '\u043E'; // о
+ private static final int CY_EL = '\u043B'; // л
+ private static final int CY_DE = '\u0434'; // д
+ private static final int CY_ZHE = '\u0436'; // ж
+ private static final int CY_E = '\u044D'; // э
+ private static final int CY_YA = '\u044F'; // я
+ private static final int CY_CHE = '\u0447'; // ч
+ private static final int CY_ES = '\u0441'; // с
+ private static final int CY_EM = '\u043C'; // м
+ private static final int CY_I = '\u0438'; // и
+ private static final int CY_TE = '\u0442'; // т
+ private static final int CY_SOFT_SIGN = '\u044C'; // ь
+ private static final int CY_BE = '\u0431'; // б
+ private static final int CY_YU = '\u044E'; // ю
+ final static int[] PROXIMITY = {
+ // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
+ // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
+ // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
+ CY_SHORT_I, CY_TSE, CY_EF, CY_YERU, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_TSE, CY_SHORT_I, CY_EF, CY_YERU, CY_VE, CY_U, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_U, CY_TSE, CY_YERU, CY_VE, CY_A, CY_KA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_KA, CY_U, CY_VE, CY_A, CY_PE, CY_IE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_IE, CY_KA, CY_A, CY_PE, CY_ER, CY_EN, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_EN, CY_IE, CY_PE, CY_ER, CY_O, CY_GHE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_GHE, CY_EN, CY_ER, CY_O, CY_EL, CY_SHA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_SHA, CY_GHE, CY_O, CY_EL, CY_DE, CY_SHCHA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_SHCHA, CY_SHA, CY_EL, CY_DE, CY_ZHE, CY_ZE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ZE, CY_SHCHA, CY_DE, CY_ZHE, CY_E, CY_HA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_HA, CY_ZE, CY_ZHE, CY_E, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ // Proximity for row 2. See comment above about size.
+ CY_EF, CY_SHORT_I, CY_TSE, CY_YERU, CY_YA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_YERU, CY_SHORT_I, CY_TSE, CY_U, CY_EF, CY_VE, CY_YA, CY_CHE,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_VE, CY_TSE, CY_U, CY_KA, CY_YERU, CY_A, CY_YA, CY_CHE,
+ CY_ES, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_A, CY_U, CY_KA, CY_IE, CY_VE, CY_PE, CY_CHE, CY_ES,
+ CY_EM, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_PE, CY_KA, CY_IE, CY_EN, CY_A, CY_ER, CY_ES, CY_EM,
+ CY_I, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ER, CY_IE, CY_EN, CY_GHE, CY_PE, CY_O, CY_EM, CY_I,
+ CY_TE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_O, CY_EN, CY_GHE, CY_SHA, CY_ER, CY_EL, CY_I, CY_TE,
+ CY_SOFT_SIGN, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_EL, CY_GHE, CY_SHA, CY_SHCHA, CY_O, CY_DE, CY_TE, CY_SOFT_SIGN,
+ CY_BE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_DE, CY_SHA, CY_SHCHA, CY_ZE, CY_EL, CY_ZHE, CY_SOFT_SIGN, CY_BE,
+ CY_YU, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ZHE, CY_SHCHA, CY_ZE, CY_HA, CY_DE, CY_E, CY_BE, CY_YU,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_E, CY_ZE, CY_HA, CY_YU, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ // Proximity for row 3. See comment above about size.
+ CY_YA, CY_EF, CY_YERU, CY_VE, CY_CHE, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_CHE, CY_YERU, CY_VE, CY_A, CY_YA, CY_ES, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ES, CY_VE, CY_A, CY_PE, CY_CHE, CY_EM, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_EM, CY_A, CY_PE, CY_ER, CY_ES, CY_I, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_I, CY_PE, CY_ER, CY_O, CY_EM, CY_TE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_TE, CY_ER, CY_O, CY_EL, CY_I, CY_SOFT_SIGN, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_SOFT_SIGN, CY_O, CY_EL, CY_DE, CY_TE, CY_BE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_BE, CY_EL, CY_DE, CY_ZHE, CY_SOFT_SIGN, CY_YU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_YU, CY_DE, CY_ZHE, CY_E, CY_BE, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, 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);
+ }
+ static int getIndexOf(int characterCode) {
+ return computeIndex(characterCode, INDICES);
+ }
+ }
+
+ private static final class Greek {
+ final private static TreeMap<Integer, Integer> INDICES = CollectionUtils.newTreeMap();
+ // TODO: The following table is solely based on the keyboard layout. Consult with Greek
+ // speakers on commonly misspelled words/letters.
+ /*
+ The Greek layout this represents looks like the following:
+ ; ς ε ρ τ υ θ ι ο π
+ α σ δ φ γ η ξ κ λ
+ ζ χ ψ ω β ν μ
+
+ This gives us the following table:
+ 'ς', 'ε', 'α', 'σ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ε', 'ς', 'ρ', 'σ', 'δ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ρ', 'ε', 'τ', 'δ', 'φ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'τ', 'ρ', 'υ', 'φ', 'γ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'υ', 'τ', 'θ', 'γ', 'η', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'θ', 'υ', 'ι', 'η', 'ξ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ι', 'θ', 'ο', 'ξ', 'κ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ο', 'ι', 'π', 'κ', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'π', 'ο', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'α', 'ς', 'σ', 'ζ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'σ', 'ς', 'ε', 'α', 'δ', 'ζ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'δ', 'ε', 'ρ', 'σ', 'φ', 'ζ', 'χ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'φ', 'ρ', 'τ', 'δ', 'γ', 'χ', 'ψ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'γ', 'τ', 'υ', 'φ', 'η', 'ψ', 'ω', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'η', 'υ', 'θ', 'γ', 'ξ', 'ω', 'β', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ξ', 'θ', 'ι', 'η', 'κ', 'β', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'κ', 'ι', 'ο', 'ξ', 'λ', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'λ', 'ο', 'π', 'κ', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'ζ', 'α', 'σ', 'δ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'χ', 'σ', 'δ', 'φ', 'ζ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ψ', 'δ', 'φ', 'γ', 'χ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ω', 'φ', 'γ', 'η', 'ψ', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'β', 'γ', 'η', 'ξ', 'ω', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ν', 'η', 'ξ', 'κ', 'β', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'μ', 'ξ', 'κ', 'λ', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ Using the following characters:
+ */
+ private static final int GR_FINAL_SIGMA = '\u03C2'; // ς
+ private static final int GR_EPSILON = '\u03B5'; // ε
+ private static final int GR_RHO = '\u03C1'; // ρ
+ private static final int GR_TAU = '\u03C4'; // τ
+ private static final int GR_UPSILON = '\u03C5'; // υ
+ private static final int GR_THETA = '\u03B8'; // θ
+ private static final int GR_IOTA = '\u03B9'; // ι
+ private static final int GR_OMICRON = '\u03BF'; // ο
+ private static final int GR_PI = '\u03C0'; // π
+ private static final int GR_ALPHA = '\u03B1'; // α
+ private static final int GR_SIGMA = '\u03C3'; // σ
+ private static final int GR_DELTA = '\u03B4'; // δ
+ private static final int GR_PHI = '\u03C6'; // φ
+ private static final int GR_GAMMA = '\u03B3'; // γ
+ private static final int GR_ETA = '\u03B7'; // η
+ private static final int GR_XI = '\u03BE'; // ξ
+ private static final int GR_KAPPA = '\u03BA'; // κ
+ private static final int GR_LAMDA = '\u03BB'; // λ
+ private static final int GR_ZETA = '\u03B6'; // ζ
+ private static final int GR_CHI = '\u03C7'; // χ
+ private static final int GR_PSI = '\u03C8'; // ψ
+ private static final int GR_OMEGA = '\u03C9'; // ω
+ private static final int GR_BETA = '\u03B2'; // β
+ private static final int GR_NU = '\u03BD'; // ν
+ private static final int GR_MU = '\u03BC'; // μ
+ final static int[] PROXIMITY = {
+ // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
+ // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
+ // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
+ GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_SIGMA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_EPSILON, GR_FINAL_SIGMA, GR_RHO, GR_SIGMA, GR_DELTA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_RHO, GR_EPSILON, GR_TAU, GR_DELTA, GR_PHI, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_TAU, GR_RHO, GR_UPSILON, GR_PHI, GR_GAMMA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_UPSILON, GR_TAU, GR_THETA, GR_GAMMA, GR_ETA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_THETA, GR_UPSILON, GR_IOTA, GR_ETA, GR_XI, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_IOTA, GR_THETA, GR_OMICRON, GR_XI, GR_KAPPA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_OMICRON, GR_IOTA, GR_PI, GR_KAPPA, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_PI, GR_OMICRON, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ GR_ALPHA, GR_FINAL_SIGMA, GR_SIGMA, GR_ZETA, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_SIGMA, GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_DELTA, GR_ZETA, GR_CHI, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_DELTA, GR_EPSILON, GR_RHO, GR_SIGMA, GR_PHI, GR_ZETA, GR_CHI, GR_PSI,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_PHI, GR_RHO, GR_TAU, GR_DELTA, GR_GAMMA, GR_CHI, GR_PSI, GR_OMEGA,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_GAMMA, GR_TAU, GR_UPSILON, GR_PHI, GR_ETA, GR_PSI, GR_OMEGA, GR_BETA,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_ETA, GR_UPSILON, GR_THETA, GR_GAMMA, GR_XI, GR_OMEGA, GR_BETA, GR_NU,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_XI, GR_THETA, GR_IOTA, GR_ETA, GR_KAPPA, GR_BETA, GR_NU, GR_MU,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_KAPPA, GR_IOTA, GR_OMICRON, GR_XI, GR_LAMDA, GR_NU, GR_MU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_LAMDA, GR_OMICRON, GR_PI, GR_KAPPA, GR_MU, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ GR_ZETA, GR_ALPHA, GR_SIGMA, GR_DELTA, GR_CHI, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_CHI, GR_SIGMA, GR_DELTA, GR_PHI, GR_ZETA, GR_PSI, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_PSI, GR_DELTA, GR_PHI, GR_GAMMA, GR_CHI, GR_OMEGA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_OMEGA, GR_PHI, GR_GAMMA, GR_ETA, GR_PSI, GR_BETA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_BETA, GR_GAMMA, GR_ETA, GR_XI, GR_OMEGA, GR_NU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_NU, GR_ETA, GR_XI, GR_KAPPA, GR_BETA, GR_MU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_MU, GR_XI, GR_KAPPA, GR_LAMDA, GR_NU, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
};
@@ -183,6 +433,8 @@ public final class SpellCheckerProximityInfo {
return Latin.PROXIMITY;
case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
return Cyrillic.PROXIMITY;
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ return Greek.PROXIMITY;
default:
throw new RuntimeException("Wrong script supplied: " + script);
}
@@ -194,6 +446,8 @@ public final class SpellCheckerProximityInfo {
return Latin.getIndexOf(codePoint);
case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
return Cyrillic.getIndexOf(codePoint);
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ return Greek.getIndexOf(codePoint);
default:
throw new RuntimeException("Wrong script supplied: " + script);
}