From 2fa21f5854e1565deb139e0bf22719fecc5340bc Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 20 Jan 2011 22:52:02 +0900 Subject: Add input method subtype selector and IME settings dialog Bug: 3351762 Change-Id: Ic1767faac6d4470a89cacb851d449ac53b2f8205 --- java/src/com/android/inputmethod/latin/Utils.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index d2582b115..5059860d7 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -23,6 +23,7 @@ import android.os.HandlerThread; import android.os.Process; import android.text.format.DateUtils; import android.util.Log; +import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import java.io.BufferedReader; @@ -97,6 +98,13 @@ public class Utils { || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; } + public static String getInputMethodId(InputMethodManager imm, String packageName) { + for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) { + if (imi.getPackageName().equals(packageName)) + return imi.getId(); + } + throw new RuntimeException("Can not find input method id for " + packageName); + } public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions) { // Safety net for auto correction. -- cgit v1.2.3-83-g751a From 58c49b91322847dc453742cb34c2899da9b44479 Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 27 Jan 2011 03:23:39 +0900 Subject: Fix auto-correction threshold and promote full matched words Bug: 3374359 Bug: 3278422 "zbe" will be auto corrected to "be" by fixing s-line "teh" will be auto corrected to "the" by promotion of full matched words Change-Id: I314c632820e4e0b1501edeca60ada205d291451f --- java/src/com/android/inputmethod/latin/Suggest.java | 2 +- java/src/com/android/inputmethod/latin/Utils.java | 5 ++++- native/src/defines.h | 1 + native/src/unigram_dictionary.cpp | 18 ++++++++++++------ native/src/unigram_dictionary.h | 2 +- 5 files changed, 19 insertions(+), 9 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1772b2669..d5ed1f83b 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -290,7 +290,7 @@ public class Suggest implements Dictionary.WordCallback { typedWord, mSuggestions.get(0), mPriorities[0]); if (LatinImeLogger.sDBG) { Log.d(TAG, "Normalized " + typedWord + "," + mSuggestions.get(0) + "," - + mPriorities[0] + normalizedScore + + mPriorities[0] + ", " + normalizedScore + "(" + mAutoCorrectionThreshold + ")"); } if (normalizedScore >= mAutoCorrectionThreshold) { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 5059860d7..53009e4a6 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -267,9 +267,12 @@ public class Utils { public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) { final int beforeLength = before.length(); final int afterLength = after.length(); + if (beforeLength == 0 || afterLength == 0) return 0; final int distance = editDistance(before, after); + // If afterLength < beforeLength, the algorithm is suggesting a word by excessive character + // correction. final double maximumScore = MAX_INITIAL_SCORE - * Math.pow(TYPED_LETTER_MULTIPLIER, beforeLength) + * Math.pow(TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength)) * FULL_WORD_MULTIPLYER; // add a weight based on edit distance. // distance <= max(afterLength, beforeLength) == afterLength, diff --git a/native/src/defines.h b/native/src/defines.h index 71aaf28ae..7374526ca 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -134,6 +134,7 @@ static void prof_out(void) { #define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75 #define WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE 75 #define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 60 +#define FULL_MATCHED_WORDS_PROMOTION_RATE 120 // This should be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java // This is only used for the size of array. Not to be used in c functions. diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index 3f9bcd758..06dd39aaa 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -347,9 +347,9 @@ void UnigramDictionary::getWordsRec(const int childrenCount, const int pos, cons } } -inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int snr, - const int skipPos, const int excessivePos, const int transposedPos, const int freq, - const bool sameLength) { +inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int depth, + const int snr, const int skipPos, const int excessivePos, const int transposedPos, + const int freq, const bool sameLength) { // TODO: Demote by edit distance int finalFreq = freq * snr; if (skipPos >= 0) multiplyRate(WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE, &finalFreq); @@ -361,6 +361,12 @@ inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE, &finalFreq); } } + int lengthFreq = TYPED_LETTER_MULTIPLIER; + for (int i = 0; i < depth; ++i) lengthFreq *= TYPED_LETTER_MULTIPLIER; + if (depth > 1 && lengthFreq == snr) { + if (DEBUG_DICT) LOGI("Found full matched word."); + multiplyRate(FULL_MATCHED_WORDS_PROMOTION_RATE, &finalFreq); + } if (sameLength && skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER; return finalFreq; } @@ -369,8 +375,8 @@ inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLe unsigned short *word, const int inputIndex, const int depth, const int snr, int *nextLetters, const int nextLettersSize, const int skipPos, const int excessivePos, const int transposedPos, const int freq) { - const int finalFreq = calculateFinalFreq(inputIndex, snr, skipPos, excessivePos, transposedPos, - freq, false); + const int finalFreq = calculateFinalFreq(inputIndex, depth, snr, skipPos, excessivePos, + transposedPos, freq, false); if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq); if (depth >= mInputLength && skipPos < 0) { registerNextLetter(mWord[mInputLength], nextLetters, nextLettersSize); @@ -382,7 +388,7 @@ inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsSameAsInputLength( const int skipPos, const int excessivePos, const int transposedPos, const int freq, const int addedWeight) { if (sameAsTyped(word, depth + 1)) return; - const int finalFreq = calculateFinalFreq(inputIndex, snr * addedWeight, skipPos, + const int finalFreq = calculateFinalFreq(inputIndex, depth, snr * addedWeight, skipPos, excessivePos, transposedPos, freq, true); // Proximity collection will promote a word of the same length as what user typed. if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq); diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h index 7f7b7bd21..95f965586 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -52,7 +52,7 @@ private: const int excessivePos, const int transposedPos, int *nextLetters, const int nextLettersSize); void registerNextLetter(unsigned short c, int *nextLetters, int nextLettersSize); - int calculateFinalFreq(const int inputIndex, const int snr, const int skipPos, + int calculateFinalFreq(const int inputIndex, const int depth, const int snr, const int skipPos, const int excessivePos, const int transposedPos, const int freq, const bool sameLength); void onTerminalWhenUserTypedLengthIsGreaterThanInputLength(unsigned short *word, const int inputIndex, const int depth, const int snr, int *nextLetters, -- cgit v1.2.3-83-g751a From 14e427d5bb13d59d23fb317ef90a6c44ae279425 Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 27 Jan 2011 01:43:06 +0900 Subject: Fix safety net not to be enabled at aggressive autocompletion mode Bug: 3374359 Change-Id: I7b1dbeb64a87dda05397c236bb58da292f819471 --- java/src/com/android/inputmethod/latin/LatinIME.java | 2 +- java/src/com/android/inputmethod/latin/Suggest.java | 4 ++++ java/src/com/android/inputmethod/latin/Utils.java | 10 +++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index c439efe4c..8166e0b4e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1580,7 +1580,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { - if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords)) { + if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) { mBestWord = typedWord; } else if (suggestedWords.hasAutoCorrectionWord()) { mBestWord = suggestedWords.getWord(1); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1772b2669..04c63be51 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -163,6 +163,10 @@ public class Suggest implements Dictionary.WordCallback { mAutoCorrectionThreshold = threshold; } + public boolean isAggressiveAutoCorrectionMode() { + return (mAutoCorrectionThreshold == 0); + } + /** * Number of suggestions to generate from the input key sequence. This has * to be a number between 1 and 100 (inclusive). diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 5059860d7..bb7239daf 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -38,6 +38,7 @@ import java.util.Date; public class Utils { private static final String TAG = Utils.class.getSimpleName(); + private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; private static boolean DBG = LatinImeLogger.sDBG; /** @@ -106,11 +107,18 @@ public class Utils { throw new RuntimeException("Can not find input method id for " + packageName); } - public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions) { + public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions, + Suggest suggest) { // Safety net for auto correction. // Actually if we hit this safety net, it's actually a bug. if (suggestions.size() <= 1 || suggestions.mTypedWordValid) return false; + // If user selected aggressive auto correction mode, there is no need to use the safety + // net. + if (suggest.isAggressiveAutoCorrectionMode()) return false; CharSequence typedWord = suggestions.getWord(0); + // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH, + // we should not use net because relatively edit distance can be big. + if (typedWord.length() < MINIMUM_SAFETY_NET_CHAR_LENGTH) return false; CharSequence candidateWord = suggestions.getWord(1); final int typedWordLength = typedWord.length(); final int maxEditDistanceOfNativeDictionary = typedWordLength < 5 ? 2 : typedWordLength / 2; -- cgit v1.2.3-83-g751a From faf437b5078e882b630706cd315c335f204ab861 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 28 Jan 2011 12:40:27 +0900 Subject: Add hack to translate sudden move to up/down events This change also gets rid of unnecessary debug messages. Bug: 3400735 Change-Id: I3f003b1c2b553a2f841d4880f348a012d2d9c8ad --- .../inputmethod/keyboard/LatinKeyboardView.java | 10 ++++- .../inputmethod/keyboard/PointerTracker.java | 43 +++++++++++++--------- java/src/com/android/inputmethod/latin/Utils.java | 7 +++- 3 files changed, 40 insertions(+), 20 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 94294e40a..af2fd5ce1 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -16,6 +16,7 @@ package com.android.inputmethod.keyboard; +import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.voice.VoiceIMEConnector; @@ -23,10 +24,13 @@ import android.content.Context; import android.graphics.Canvas; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; // TODO: We should remove this class public class LatinKeyboardView extends KeyboardView { + private static final String TAG = LatinKeyboardView.class.getSimpleName(); + private static boolean DEBUG_MODE = LatinImeLogger.sDBG; /** Whether we've started dropping move events because we found a big jump */ private boolean mDroppingEvents; @@ -208,7 +212,11 @@ public class LatinKeyboardView extends KeyboardView { if (keyboard == null) return true; // If there was a sudden jump, return without processing the actual motion event. - if (handleSuddenJump(me)) return true; + if (handleSuddenJump(me)) { + if (DEBUG_MODE) + Log.w(TAG, "onTouchEvent: ignore sudden jump " + me); + return true; + } // Reset any bounding box controls in the keyboard if (me.getAction() == MotionEvent.ACTION_DOWN) { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index cf379f0bf..a981f724f 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -17,6 +17,7 @@ package com.android.inputmethod.keyboard; import com.android.inputmethod.keyboard.KeyboardView.UIHandler; +import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import android.content.res.Resources; @@ -31,6 +32,7 @@ public class PointerTracker { private static final boolean DEBUG_EVENT = false; private static final boolean DEBUG_MOVE_EVENT = false; private static final boolean DEBUG_LISTENER = false; + private static boolean DEBUG_MODE = LatinImeLogger.sDBG; public interface UIProxy { public void invalidateKey(Key key); @@ -62,6 +64,7 @@ public class PointerTracker { private Keyboard mKeyboard; private Key[] mKeys; private int mKeyHysteresisDistanceSquared = -1; + private int mKeyQuarterWidthSquared; private final PointerTrackerKeyState mKeyState; @@ -166,6 +169,8 @@ public class PointerTracker { mKeyboard = keyboard; mKeys = keys; mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); + final int keyQuarterWidth = keyboard.getKeyWidth() / 4; + mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; // Mark that keyboard layout has been changed. mKeyboardLayoutHasBeenChanged = true; } @@ -268,10 +273,6 @@ public class PointerTracker { if (DEBUG_EVENT) printTouchEvent("onDownEvent:", x, y, eventTime); - // TODO: up-to-down filter, if (down-up) is less than threshold, removeMessage(UP, this) in - // Handler, and just ignore this down event. - // TODO: down-to-up filter, just record down time. do not enqueue pointer now. - // Naive up-to-down noise filter. final long deltaT = eventTime - mKeyState.getUpTime(); if (deltaT < mTouchNoiseThresholdMillis) { @@ -279,8 +280,9 @@ public class PointerTracker { final int dy = y - mKeyState.getLastY(); final int distanceSquared = (dx * dx + dy * dy); if (distanceSquared < mTouchNoiseThresholdDistanceSquared) { - Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT - + " distance=" + distanceSquared); + if (DEBUG_MODE) + Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT + + " distance=" + distanceSquared); setAlreadyProcessed(); return; } @@ -333,9 +335,8 @@ public class PointerTracker { return; final PointerTrackerKeyState keyState = mKeyState; - // TODO: down-to-up filter, if (eventTime-downTime) is less than threshold, just ignore - // this move event. Otherwise fire {@link onDownEventInternal} and continue. - + final int lastX = keyState.getLastX(); + final int lastY = keyState.getLastY(); int keyIndex = keyState.onMoveKey(x, y); final Key oldKey = getKey(keyState.getKeyIndex()); if (isValidKeyIndex(keyIndex)) { @@ -365,8 +366,22 @@ public class PointerTracker { keyState.onMoveToNewKey(keyIndex, x, y); startLongPressTimer(keyIndex); } else { - setAlreadyProcessed(); - showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY); + // HACK: On some devices, quick successive touches may be translated to sudden + // move by touch panel firmware. This hack detects the case and translates the + // move event to successive up and down events. + final int dx = x - lastX; + final int dy = y - lastY; + final int lastMoveSquared = dx * dx + dy * dy; + if (lastMoveSquared >= mKeyQuarterWidthSquared) { + if (DEBUG_MODE) + Log.w(TAG, String.format("onMoveEvent: sudden move is translated to " + + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); + onUpEventInternal(lastX, lastY, eventTime); + onDownEventInternal(x, y, eventTime); + } else { + setAlreadyProcessed(); + showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY); + } return; } } @@ -389,17 +404,11 @@ public class PointerTracker { showKeyPreviewAndUpdateKeyGraphics(mKeyState.getKeyIndex()); } - // TODO: up-to-down filter, if delayed UP message is fired, invoke {@link onUpEventInternal}. - public void onUpEvent(int x, int y, long eventTime, PointerTrackerQueue queue) { if (ENABLE_ASSERTION) checkAssertion(queue); if (DEBUG_EVENT) printTouchEvent("onUpEvent :", x, y, eventTime); - // TODO: up-to-down filter, just sendDelayedMessage(UP, this) to Handler. - // TODO: down-to-up filter, if (eventTime-downTime) is less than threshold, just ignore - // this up event. Otherwise fire {@link onDownEventInternal} and {@link onUpEventInternal}. - if (queue != null) { if (isModifier()) { // Before processing an up event of modifier key, all pointers already being diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index e6ec48cd2..e980d3a30 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -128,8 +128,11 @@ public class Utils { + ", " + maxEditDistanceOfNativeDictionary); } if (distance > maxEditDistanceOfNativeDictionary) { - Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. " - + "Turning off auto-correction."); + if (DBG) { + Log.d(TAG, "Safety net: before = " + typedWord + ", after = " + candidateWord); + Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. " + + "Turning off auto-correction."); + } return true; } else { return false; -- cgit v1.2.3-83-g751a