Merge "Add subtype languages" into honeycomb
diff --git a/java/res/values-xlarge/config.xml b/java/res/values-xlarge/config.xml
index d686460..004b39b 100644
--- a/java/res/values-xlarge/config.xml
+++ b/java/res/values-xlarge/config.xml
@@ -24,6 +24,8 @@
     <bool name="config_enable_show_voice_key_option">false</bool>
     <bool name="config_enable_show_popup_on_keypress_option">false</bool>
     <bool name="config_enable_show_recorrection_option">false</bool>
+    <bool name="config_enable_quick_fixes_option">false</bool>
+    <bool name="config_enable_bigram_suggestions_option">false</bool>
     <bool name="config_candidate_highlight_font_color_enabled">false</bool>
     <bool name="config_swipe_down_dismiss_keyboard_enabled">false</bool>
     <bool name="config_sliding_key_input_enabled">false</bool>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index a523635..6a1b27a 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -27,12 +27,18 @@
     <bool name="config_enable_show_voice_key_option">true</bool>
     <bool name="config_enable_show_popup_on_keypress_option">true</bool>
     <bool name="config_enable_show_recorrection_option">true</bool>
+    <bool name="config_enable_quick_fixes_option">true</bool>
+    <bool name="config_enable_bigram_suggestions_option">true</bool>
+    <bool name="config_enable_usability_study_mode_option">false</bool>
     <bool name="config_candidate_highlight_font_color_enabled">true</bool>
     <bool name="config_swipe_down_dismiss_keyboard_enabled">true</bool>
     <bool name="config_sliding_key_input_enabled">true</bool>
     <bool name="config_digit_popup_characters_enabled">true</bool>
     <!-- Whether or not Popup on key press is enabled by default -->
     <bool name="config_default_popup_preview">true</bool>
+    <!-- Default values for whether quick fixes and bigram suggestions are activated -->
+    <bool name="config_default_quick_fixes">true</bool>
+    <bool name="config_default_bigram_suggestions">true</bool>
     <bool name="config_use_spacebar_language_switcher">true</bool>
     <!-- The language is never displayed if == 0, always displayed if < 0 -->
     <integer name="config_delay_before_fadeout_language_on_spacebar">-1</integer>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 9f83d9a..a664aaf 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -34,8 +34,11 @@
     <!-- Option to control whether or not to show a popup with a larger font on each key press. -->
     <string name="popup_on_keypress">Popup on keypress</string>
 
+    <!-- Category title for general settings for Android keyboard -->
+    <string name="general_category">General</string>
+
     <!-- Category title for text prediction -->
-    <string name="prediction_category">Word suggestion settings</string>
+    <string name="prediction_category">Text correction</string>
 
     <!-- Option to enable auto capitalization of sentences -->
     <string name="auto_cap">Auto-capitalization</string>
@@ -46,7 +49,7 @@
     <string name="quick_fixes_summary">Corrects commonly typed mistakes</string>
 
     <!-- Option to enable showing suggestions -->
-    <string name="prefs_show_suggestions">Show suggestions</string>
+    <string name="prefs_show_suggestions">Show correction suggestions</string>
     <!-- Description for show suggestions -->
     <string name="prefs_show_suggestions_summary">Display suggested words while typing</string>
     <string name="prefs_suggestion_visibility_show_name">Always show</string>
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 4bcb1d7..9ea801e 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,62 +18,68 @@
         android:title="@string/english_ime_settings"
         android:key="english_ime_settings">
 
-    <CheckBoxPreference
-            android:key="auto_cap"
-            android:title="@string/auto_cap"
-            android:persistent="true"
-            android:defaultValue="true"
-            />
+    <PreferenceCategory
+            android:title="@string/general_category"
+            android:key="general_settings">
 
-    <CheckBoxPreference
-            android:key="vibrate_on"
-            android:title="@string/vibrate_on_keypress"
-            android:persistent="true"
-            />
+        <CheckBoxPreference
+                android:key="auto_cap"
+                android:title="@string/auto_cap"
+                android:persistent="true"
+                android:defaultValue="true"
+                />
 
-    <CheckBoxPreference
-            android:key="sound_on"
-            android:title="@string/sound_on_keypress"
-            android:persistent="true" 
-            />
+        <CheckBoxPreference
+                android:key="vibrate_on"
+                android:title="@string/vibrate_on_keypress"
+                android:persistent="true"
+                />
 
-    <CheckBoxPreference
-            android:key="popup_on"
-            android:title="@string/popup_on_keypress"
-            android:persistent="true"
-            android:defaultValue="@bool/config_default_popup_preview"
-            />
+        <CheckBoxPreference
+                android:key="sound_on"
+                android:title="@string/sound_on_keypress"
+                android:persistent="true"
+                />
 
-    <CheckBoxPreference
-            android:key="recorrection_enabled"
-            android:title="@string/prefs_enable_recorrection"
-            android:summary="@string/prefs_enable_recorrection_summary"
-            android:persistent="true"
-            android:defaultValue="@bool/default_recorrection_enabled"
-            />
+        <CheckBoxPreference
+                android:key="popup_on"
+                android:title="@string/popup_on_keypress"
+                android:persistent="true"
+                android:defaultValue="@bool/config_default_popup_preview"
+                />
 
-    <ListPreference
-            android:key="settings_key"
-            android:title="@string/prefs_settings_key"
-            android:persistent="true"
-            android:entryValues="@array/settings_key_modes_values"
-            android:entries="@array/settings_key_modes"
-            android:defaultValue="@string/settings_key_mode_auto"
-            />
+        <CheckBoxPreference
+                android:key="recorrection_enabled"
+                android:title="@string/prefs_enable_recorrection"
+                android:summary="@string/prefs_enable_recorrection_summary"
+                android:persistent="true"
+                android:defaultValue="@bool/default_recorrection_enabled"
+                />
 
-    <ListPreference
-            android:key="voice_mode"
-            android:title="@string/voice_input"
-            android:persistent="true"
-            android:entryValues="@array/voice_input_modes_values"
-            android:entries="@array/voice_input_modes"
-            android:defaultValue="@string/voice_mode_main"
-            />
+        <ListPreference
+                android:key="settings_key"
+                android:title="@string/prefs_settings_key"
+                android:persistent="true"
+                android:entryValues="@array/settings_key_modes_values"
+                android:entries="@array/settings_key_modes"
+                android:defaultValue="@string/settings_key_mode_auto"
+                />
 
-    <PreferenceScreen
-            android:key="subtype_settings"
-            android:title="@string/language_selection_title"
-            android:summary="@string/language_selection_summary" />
+        <ListPreference
+                android:key="voice_mode"
+                android:title="@string/voice_input"
+                android:persistent="true"
+                android:entryValues="@array/voice_input_modes_values"
+                android:entries="@array/voice_input_modes"
+                android:defaultValue="@string/voice_mode_main"
+                />
+
+        <PreferenceScreen
+                android:key="subtype_settings"
+                android:title="@string/language_selection_title"
+                android:summary="@string/language_selection_summary" />
+
+    </PreferenceCategory>
 
     <PreferenceCategory
             android:title="@string/prediction_category"
@@ -88,16 +94,6 @@
             />
 
         <ListPreference
-            android:key="show_suggestions_setting"
-            android:summary="@string/prefs_show_suggestions_summary"
-            android:title="@string/prefs_show_suggestions"
-            android:persistent="true"
-            android:entryValues="@array/prefs_suggestion_visibility_values"
-            android:entries="@array/prefs_suggestion_visibilities"
-            android:defaultValue="@string/prefs_suggestion_visibility_default_value"
-            />
-
-        <ListPreference
             android:key="auto_correction_threshold"
             android:title="@string/auto_correction"
             android:summary="@string/auto_correction_summary"
@@ -107,6 +103,16 @@
             android:defaultValue="@string/auto_correction_threshold_mode_index_modest"
             />
 
+        <ListPreference
+            android:key="show_suggestions_setting"
+            android:summary="@string/prefs_show_suggestions_summary"
+            android:title="@string/prefs_show_suggestions"
+            android:persistent="true"
+            android:entryValues="@array/prefs_suggestion_visibility_values"
+            android:entries="@array/prefs_suggestion_visibilities"
+            android:defaultValue="@string/prefs_suggestion_visibility_default_value"
+            />
+
         <CheckBoxPreference
             android:key="bigram_suggestion"
             android:title="@string/bigram_suggestion"
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index ef41cb6..e9d5580 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -205,10 +205,10 @@
     @Override
     public boolean onTouchEvent(MotionEvent me) {
         LatinKeyboard keyboard = getLatinKeyboard();
+        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)) return true;
 
         // Reset any bounding box controls in the keyboard
         if (me.getAction() == MotionEvent.ACTION_DOWN) {
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index 30f4a59..d2d1f22 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -45,23 +45,22 @@
 import java.util.ArrayList;
 
 public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
-    private LatinIME mService;
-    private final ArrayList<View> mWords = new ArrayList<View>();
 
-    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<View> mWords = new ArrayList<View>();
     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 @@
             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 @@
             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 5d48d6b..4e1c56c 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -412,7 +412,7 @@
             mSuggest.close();
         }
         final SharedPreferences prefs = mPrefs;
-        mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
+        mQuickFixes = isQuickFixesEnabled(prefs);
 
         final Resources res = mResources;
         int mainDicResId = getMainDictionaryResourceId(res);
@@ -1537,7 +1537,9 @@
     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;
@@ -2075,7 +2077,7 @@
         mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON,
                 mResources.getBoolean(R.bool.config_default_popup_preview));
         mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
-        mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
+        mQuickFixes = isQuickFixesEnabled(prefs);
 
         mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
         mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
@@ -2124,6 +2126,16 @@
         mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
     }
 
+    private boolean isQuickFixesEnabled(SharedPreferences sp) {
+        final boolean showQuickFixesOption = mResources.getBoolean(
+                R.bool.config_enable_quick_fixes_option);
+        if (!showQuickFixesOption) {
+            return isAutoCorrectEnabled(sp);
+        }
+        return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
+                R.bool.config_default_quick_fixes));
+    }
+
     private boolean isAutoCorrectEnabled(SharedPreferences sp) {
         final String currentAutoCorrectionSetting = sp.getString(
                 Settings.PREF_AUTO_CORRECTION_THRESHOLD,
@@ -2134,8 +2146,13 @@
     }
 
     private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
-       // TODO: Define default value instead of 'true'.
-       return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, true);
+        final boolean showBigramSuggestionsOption = mResources.getBoolean(
+                R.bool.config_enable_bigram_suggestions_option);
+        if (!showBigramSuggestionsOption) {
+            return isAutoCorrectEnabled(sp);
+        }
+        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
+                R.bool.config_default_bigram_suggestions));
     }
 
     private void initSuggestPuncList() {
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 75ebbe7..653dbea 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
@@ -48,6 +48,7 @@
         DialogInterface.OnDismissListener, OnPreferenceClickListener {
     private static final String TAG = "Settings";
 
+    public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings";
     public static final String PREF_VIBRATE_ON = "vibrate_on";
     public static final String PREF_SOUND_ON = "sound_on";
     public static final String PREF_POPUP_ON = "popup_on";
@@ -65,6 +66,8 @@
     public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
     public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
 
+    public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
+
     // Dialog ids
     private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
 
@@ -111,40 +114,62 @@
         mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
         ensureConsistencyOfAutoCorrectionSettings();
 
+        final PreferenceGroup generalSettings =
+                (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY);
+        final PreferenceGroup textCorrectionGroup =
+                (PreferenceGroup) findPreference(PREF_PREDICTION_SETTINGS_KEY);
+
         final boolean showSettingsKeyOption = getResources().getBoolean(
                 R.bool.config_enable_show_settings_key_option);
         if (!showSettingsKeyOption) {
-            getPreferenceScreen().removePreference(mSettingsKeyPreference);
+            generalSettings.removePreference(mSettingsKeyPreference);
         }
 
         final boolean showVoiceKeyOption = getResources().getBoolean(
                 R.bool.config_enable_show_voice_key_option);
         if (!showVoiceKeyOption) {
-            getPreferenceScreen().removePreference(mVoicePreference);
+            generalSettings.removePreference(mVoicePreference);
         }
 
         Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
         if (vibrator == null || !vibrator.hasVibrator()) {
-            getPreferenceScreen().removePreference(
-                    getPreferenceScreen().findPreference(PREF_VIBRATE_ON));
+            generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
         }
 
         final boolean showSubtypeSettings = getResources().getBoolean(
                 R.bool.config_enable_show_subtype_settings);
         if (!showSubtypeSettings) {
-            getPreferenceScreen().removePreference(findPreference(PREF_SUBTYPES));
+            generalSettings.removePreference(findPreference(PREF_SUBTYPES));
         }
 
         final boolean showPopupOption = getResources().getBoolean(
                 R.bool.config_enable_show_popup_on_keypress_option);
         if (!showPopupOption) {
-            getPreferenceScreen().removePreference(findPreference(PREF_POPUP_ON));
+            generalSettings.removePreference(findPreference(PREF_POPUP_ON));
         }
 
         final boolean showRecorrectionOption = getResources().getBoolean(
                 R.bool.config_enable_show_recorrection_option);
         if (!showRecorrectionOption) {
-            getPreferenceScreen().removePreference(findPreference(PREF_RECORRECTION_ENABLED));
+            generalSettings.removePreference(findPreference(PREF_RECORRECTION_ENABLED));
+        }
+
+        final boolean showQuickFixesOption = getResources().getBoolean(
+                R.bool.config_enable_quick_fixes_option);
+        if (!showQuickFixesOption) {
+            textCorrectionGroup.removePreference(findPreference(PREF_QUICK_FIXES));
+        }
+
+        final boolean showBigramSuggestionsOption = getResources().getBoolean(
+                R.bool.config_enable_bigram_suggestions_option);
+        if (!showBigramSuggestionsOption) {
+            textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_SUGGESTIONS));
+        }
+
+        final boolean showUsabilityModeStudyOption = getResources().getBoolean(
+                R.bool.config_enable_usability_study_mode_option);
+        if (!showUsabilityModeStudyOption) {
+            getPreferenceScreen().removePreference(findPreference(PREF_USABILITY_STUDY_MODE));
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index a8454b2..24c73e8 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -31,7 +31,7 @@
  */
 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 @@
 
     static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
 
+    private static boolean DBG = LatinImeLogger.sDBG;
+
     private BinaryDictionary mMainDict;
 
     private Dictionary mUserDictionary;
@@ -93,7 +95,7 @@
     private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
     ArrayList<CharSequence> mBigramSuggestions  = new ArrayList<CharSequence>();
     private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
-    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 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 @@
                 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 @@
                             + "(" + mAutoCorrectionThreshold + ")");
                 }
                 if (normalizedScore >= mAutoCorrectionThreshold) {
-                    mHaveCorrection = true;
+                    if (DBG) {
+                        Log.d(TAG, "Auto corrected by S-threthhold.");
+                    }
+                    mHaveAutoCorrection = true;
                 }
             }
         }
@@ -331,7 +339,10 @@
                     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 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 753e5d6..d2582b1 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.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 @@
                 || 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';