From 82411d47ba7e8133ed2390c6920945e139a738ce Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 18 Jan 2011 17:22:01 +0900 Subject: [PATCH] Add a safety net for auto-correction. Bug: 3353956 Change-Id: I6a32632b2f986f0d9a07aa72f256a2c41cc09873 --- .../inputmethod/latin/CandidateView.java | 24 +++++++++--------- .../android/inputmethod/latin/LatinIME.java | 4 ++- .../android/inputmethod/latin/Suggest.java | 25 +++++++++++++------ .../com/android/inputmethod/latin/Utils.java | 25 +++++++++++++++++++ 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 30f4a59f9..d2d1f22dd 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -45,23 +45,22 @@ import android.widget.TextView; import java.util.ArrayList; public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { - private LatinIME mService; - private final ArrayList mWords = new ArrayList(); - private final TextView mPreviewText; - private final PopupWindow mPreviewPopup; - + private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); + private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); private static final int MAX_SUGGESTIONS = 16; + private final ArrayList mWords = new ArrayList(); private final boolean mConfigCandidateHighlightFontColorEnabled; + private final CharacterStyle mInvertedForegroundColorSpan; + private final CharacterStyle mInvertedBackgroundColorSpan; private final int mColorNormal; private final int mColorRecommended; private final int mColorOther; - private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); - private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); - private final CharacterStyle mInvertedForegroundColorSpan; - private final CharacterStyle mInvertedBackgroundColorSpan; + private final PopupWindow mPreviewPopup; + private final TextView mPreviewText; + private LatinIME mService; private SuggestedWords mSuggestions = SuggestedWords.EMPTY; private boolean mShowingAutoCorrectionInverted; private boolean mShowingAddToDictionary; @@ -186,9 +185,10 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo final TextView tv = (TextView)v.findViewById(R.id.candidate_word); final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info); tv.setTextColor(mColorNormal); + // TODO: Needs safety net? if (suggestions.mHasMinimalSuggestion - && ((i == 1 && !suggestions.mTypedWordValid) || - (i == 0 && suggestions.mTypedWordValid))) { + && ((i == 1 && !suggestions.mTypedWordValid) + || (i == 0 && suggestions.mTypedWordValid))) { final CharacterStyle style; if (mConfigCandidateHighlightFontColorEnabled) { style = BOLD_SPAN; @@ -329,7 +329,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mService.pickSuggestionManually(index, word); } } - + @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5d48d6b36..fff09fa97 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1537,7 +1537,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { - if (suggestedWords.hasAutoCorrectionWord()) { + if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords)) { + mBestWord = typedWord; + } else if (suggestedWords.hasAutoCorrectionWord()) { mBestWord = suggestedWords.getWord(1); } else { mBestWord = typedWord; diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index a8454b23e..24c73e8ea 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -31,7 +31,7 @@ import java.util.Arrays; */ public class Suggest implements Dictionary.WordCallback { - public static final String TAG = "Suggest"; + public static final String TAG = Suggest.class.getSimpleName(); public static final int APPROX_MAX_WORD_LENGTH = 32; @@ -64,6 +64,8 @@ public class Suggest implements Dictionary.WordCallback { static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000; + private static boolean DBG = LatinImeLogger.sDBG; + private BinaryDictionary mMainDict; private Dictionary mUserDictionary; @@ -93,7 +95,7 @@ public class Suggest implements Dictionary.WordCallback { private ArrayList mSuggestions = new ArrayList(); ArrayList mBigramSuggestions = new ArrayList(); private ArrayList mStringPool = new ArrayList(); - private boolean mHaveCorrection; + private boolean mHaveAutoCorrection; private String mLowerOriginalWord; // TODO: Remove these member variables by passing more context to addWord() callback method @@ -198,7 +200,7 @@ public class Suggest implements Dictionary.WordCallback { public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer, CharSequence prevWordForBigram) { LatinImeLogger.onStartSuggestion(prevWordForBigram); - mHaveCorrection = false; + mHaveAutoCorrection = false; mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); collectGarbage(mSuggestions, mPrefMaxSuggestions); @@ -273,7 +275,10 @@ public class Suggest implements Dictionary.WordCallback { if (mSuggestions.size() > 0 && isValidWord(typedWord) && (mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)) { - mHaveCorrection = true; + if (DBG) { + Log.d(TAG, "Auto corrected by CORRECTION_FULL."); + } + mHaveAutoCorrection = true; } } if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies); @@ -289,7 +294,10 @@ public class Suggest implements Dictionary.WordCallback { + "(" + mAutoCorrectionThreshold + ")"); } if (normalizedScore >= mAutoCorrectionThreshold) { - mHaveCorrection = true; + if (DBG) { + Log.d(TAG, "Auto corrected by S-threthhold."); + } + mHaveAutoCorrection = true; } } } @@ -331,7 +339,10 @@ public class Suggest implements Dictionary.WordCallback { canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1)); } if (canAdd) { - mHaveCorrection = true; + if (DBG) { + Log.d(TAG, "Auto corrected by AUTOTEXT."); + } + mHaveAutoCorrection = true; mSuggestions.add(i + 1, autoText); i++; } @@ -374,7 +385,7 @@ public class Suggest implements Dictionary.WordCallback { } public boolean hasMinimalCorrection() { - return mHaveCorrection; + return mHaveAutoCorrection; } private boolean compareCaseInsensitive(final String mLowerOriginalWord, diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 753e5d64f..d2582b115 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -36,6 +36,8 @@ import java.text.SimpleDateFormat; import java.util.Date; public class Utils { + private static final String TAG = Utils.class.getSimpleName(); + private static boolean DBG = LatinImeLogger.sDBG; /** * Cancel an {@link AsyncTask}. @@ -95,6 +97,29 @@ public class Utils { || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; } + + public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions) { + // 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; + CharSequence typedWord = suggestions.getWord(0); + CharSequence candidateWord = suggestions.getWord(1); + final int typedWordLength = typedWord.length(); + final int maxEditDistanceOfNativeDictionary = typedWordLength < 5 ? 2 : typedWordLength / 2; + final int distance = Utils.editDistance(typedWord, candidateWord); + if (DBG) { + Log.d(TAG, "Autocorrected edit distance = " + distance + + ", " + maxEditDistanceOfNativeDictionary); + } + if (distance > maxEditDistanceOfNativeDictionary) { + Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. " + + "Turning off auto-correction."); + return true; + } else { + return false; + } + } + /* package */ static class RingCharBuffer { private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';