Merge "Disable auto-correct when previous suggestion candidates are shown" into honeycomb
diff --git a/java/res/drawable-mdpi/sym_keyboard_settings_holo.png b/java/res/drawable-mdpi/sym_keyboard_settings_holo.png
new file mode 100644
index 0000000..ad7618f
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_settings_holo.png
Binary files differ
diff --git a/java/res/values-xlarge/config.xml b/java/res/values-xlarge/config.xml
index 410b5e1..9129717 100644
--- a/java/res/values-xlarge/config.xml
+++ b/java/res/values-xlarge/config.xml
@@ -22,6 +22,7 @@
     <bool name="config_enable_show_settings_key_option">false</bool>
     <bool name="config_enable_show_subtype_settings">false</bool>
     <bool name="config_enable_show_voice_key_option">false</bool>
+    <bool name="config_enable_show_popup_on_keypress_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 11b92e7..e582107 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -25,6 +25,7 @@
     <bool name="config_enable_show_settings_key_option">true</bool>
     <bool name="config_enable_show_subtype_settings">true</bool>
     <bool name="config_enable_show_voice_key_option">true</bool>
+    <bool name="config_enable_show_popup_on_keypress_option">true</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>
diff --git a/java/res/xml-xlarge/kbd_key_styles.xml b/java/res/xml-xlarge/kbd_key_styles.xml
index efbad5b..26659a2 100644
--- a/java/res/xml-xlarge/kbd_key_styles.xml
+++ b/java/res/xml-xlarge/kbd_key_styles.xml
@@ -66,6 +66,12 @@
                 latin:popupCharacters="@string/alternates_for_smiley"
                 latin:maxPopupKeyboardColumn="5" />
             <key-style
+                latin:styleName="settingsKeyStyle"
+                latin:code="@integer/key_settings"
+                latin:keyIcon="@drawable/sym_keyboard_settings_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_settings"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
                 latin:styleName="micKeyStyle"
                 latin:code="@integer/key_voice"
                 latin:keyIcon="@drawable/sym_keyboard_voice_holo"
@@ -114,6 +120,12 @@
                 latin:popupCharacters="@string/alternates_for_smiley"
                 latin:maxPopupKeyboardColumn="5" />
             <key-style
+                latin:styleName="settingsKeyStyle"
+                latin:code="@integer/key_settings"
+                latin:keyIcon="@drawable/sym_bkeyboard_settings"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_settings"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
                 latin:styleName="micKeyStyle"
                 latin:code="@integer/key_voice"
                 latin:keyIcon="@drawable/sym_bkeyboard_mic"
diff --git a/java/res/xml-xlarge/kbd_number.xml b/java/res/xml-xlarge/kbd_number.xml
index c2cbb31..875548b 100644
--- a/java/res/xml-xlarge/kbd_number.xml
+++ b/java/res/xml-xlarge/kbd_number.xml
@@ -120,7 +120,10 @@
         <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
              the touch event on the area, "space" is intentionally not marked as a left edge key. -->
         <Spacer
-            latin:horizontalGap="16.406%p" />
+            latin:horizontalGap="8.362%p" />
+        <Key
+            latin:keyStyle="settingsKeyStyle"
+            latin:keyWidth="8.042%p" />
         <Key
             latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
             latin:keyWidth="24.127%p" />
diff --git a/java/res/xml-xlarge/kbd_phone.xml b/java/res/xml-xlarge/kbd_phone.xml
index c320ebb..b9444ad 100644
--- a/java/res/xml-xlarge/kbd_phone.xml
+++ b/java/res/xml-xlarge/kbd_phone.xml
@@ -128,10 +128,13 @@
         <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
              the touch event on the area, "space" is intentionally not marked as a left edge key. -->
         <Spacer
-            latin:horizontalGap="20.427%p" />
+            latin:horizontalGap="12.340%p" />
+        <Key
+            latin:keyStyle="settingsKeyStyle"
+            latin:keyWidth="8.042%p" />
         <Key
             latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
-            latin:keyWidth="16.085%p" />
+            latin:keyWidth="16.084%p" />
         <Spacer
             latin:horizontalGap="8.479%p" />
         <Key
diff --git a/java/res/xml-xlarge/kbd_phone_symbols.xml b/java/res/xml-xlarge/kbd_phone_symbols.xml
index da15b5a..690bcde 100644
--- a/java/res/xml-xlarge/kbd_phone_symbols.xml
+++ b/java/res/xml-xlarge/kbd_phone_symbols.xml
@@ -140,7 +140,10 @@
         <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
              the touch event on the area, "space" is intentionally not marked as a left edge key. -->
         <Spacer
-            latin:horizontalGap="16.406%p" />
+            latin:horizontalGap="8.362%p" />
+        <Key
+            latin:keyStyle="settingsKeyStyle"
+            latin:keyWidth="8.042%p" />
         <Key
             latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
             latin:keyWidth="24.127%p" />
diff --git a/java/res/xml-xlarge/kbd_qwerty_row4.xml b/java/res/xml-xlarge/kbd_qwerty_row4.xml
index 98acfc1..9d0fd81 100644
--- a/java/res/xml-xlarge/kbd_qwerty_row4.xml
+++ b/java/res/xml-xlarge/kbd_qwerty_row4.xml
@@ -26,7 +26,9 @@
         latin:keyWidth="8.042%p"
     >
         <Spacer
-            latin:horizontalGap="16.404%p" />
+            latin:horizontalGap="8.362%p" />
+        <Key
+            latin:keyStyle="settingsKeyStyle" />
         <switch>
             <case
                 latin:mode="email"
diff --git a/java/res/xml-xlarge/kbd_symbols.xml b/java/res/xml-xlarge/kbd_symbols.xml
index d804f79..e56cc92 100644
--- a/java/res/xml-xlarge/kbd_symbols.xml
+++ b/java/res/xml-xlarge/kbd_symbols.xml
@@ -149,7 +149,9 @@
         latin:keyWidth="8.042%p"
     >
         <Spacer
-            latin:horizontalGap="16.404%p" />
+            latin:horizontalGap="8.362%p" />
+        <Key
+            latin:keyStyle="settingsKeyStyle" />
         <Key
             latin:keyLabel="/" />
         <Key
diff --git a/java/res/xml-xlarge/kbd_symbols_shift.xml b/java/res/xml-xlarge/kbd_symbols_shift.xml
index db33aaa..f7cf24a 100644
--- a/java/res/xml-xlarge/kbd_symbols_shift.xml
+++ b/java/res/xml-xlarge/kbd_symbols_shift.xml
@@ -135,7 +135,9 @@
         latin:keyWidth="8.042%p"
     >
         <Spacer
-            latin:horizontalGap="32.488%p" />
+            latin:horizontalGap="24.446%p" />
+        <Key
+            latin:keyStyle="settingsKeyStyle" />
         <Key
             latin:keyStyle="spaceKeyStyle"
             latin:keyWidth="37.454%p" />
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index cd4143e..b289766 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -133,14 +133,17 @@
     private Resources mResources;
     private SharedPreferences mPrefs;
 
+    // These variables are initialized according to the {@link EditorInfo#inputType}.
+    private boolean mAutoSpace;
+    private boolean mInputTypeNoAutoCorrect;
+    private boolean mIsSettingsSuggestionStripOn;
+    private boolean mApplicationSpecifiedCompletionOn;
+
     private final StringBuilder mComposing = new StringBuilder();
     private WordComposer mWord = new WordComposer();
     private CharSequence mBestWord;
     private boolean mHasValidSuggestions;
-    private boolean mIsSettingsSuggestionStripOn;
-    private boolean mApplicationSpecifiedCompletionOn;
     private boolean mHasDictionary;
-    private boolean mAutoSpace;
     private boolean mJustAddedAutoSpace;
     private boolean mAutoCorrectEnabled;
     private boolean mReCorrectionEnabled;
@@ -164,9 +167,6 @@
     private int mLastSelectionEnd;
     private SuggestedWords mSuggestPuncList;
 
-    // Input type is such that we should not auto-correct
-    private boolean mInputTypeNoAutoCorrect;
-
     // Indicates whether the suggestion strip is to be on in landscape
     private boolean mJustAccepted;
     private boolean mJustReverted;
@@ -507,24 +507,62 @@
 
         if (mRefreshKeyboardRequired) {
             mRefreshKeyboardRequired = false;
-            onKeyboardLanguageChanged();
+            onRefreshKeyboard();
         }
 
         TextEntryState.newSession(this);
 
-        // Most such things we decide below in the switch statement, but we need to know
-        // now whether this is a password text field, because we need to know now (before
-        // the switch statement) whether we want to enable the voice button.
-        int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
-        mVoiceConnector.resetVoiceStates(isPasswordVariation(variation));
+        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
+        // know now whether this is a password text field, because we need to know now whether we
+        // want to enable the voice button.
+        mVoiceConnector.resetVoiceStates(isPasswordVariation(
+                attribute.inputType & InputType.TYPE_MASK_VARIATION));
+
+        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
+
+        inputView.closing();
+        mEnteredText = null;
+        mComposing.setLength(0);
+        mHasValidSuggestions = false;
+        mDeleteCount = 0;
+        mJustAddedAutoSpace = false;
+
+        loadSettings(attribute);
+        if (mSubtypeSwitcher.isKeyboardMode()) {
+            switcher.loadKeyboard(mode, attribute.imeOptions,
+                    mVoiceConnector.isVoiceButtonEnabled(),
+                    mVoiceConnector.isVoiceButtonOnPrimary());
+            switcher.updateShiftState();
+        }
+
+        setCandidatesViewShownInternal(isCandidateStripVisible(),
+                false /* needsInputViewShown */ );
+        // Delay updating suggestions because keyboard input view may not be shown at this point.
+        mHandler.postUpdateSuggestions();
+
+        updateCorrectionMode();
+
+        inputView.setPreviewEnabled(mPopupOn);
+        inputView.setProximityCorrectionEnabled(true);
+        // If we just entered a text field, maybe it has some old text that requires correction
+        checkReCorrectionOnStart();
+        inputView.setForeground(true);
+
+        mVoiceConnector.onStartInputView(inputView.getWindowToken());
+
+        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
+    }
+
+    private int initializeInputAttributesAndGetMode(int inputType) {
+        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+        mAutoSpace = false;
         mInputTypeNoAutoCorrect = false;
         mIsSettingsSuggestionStripOn = false;
         mApplicationSpecifiedCompletionOn = false;
         mApplicationSpecifiedCompletions = null;
-        mEnteredText = null;
 
         final int mode;
-        switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
+        switch (inputType & InputType.TYPE_MASK_CLASS) {
             case InputType.TYPE_CLASS_NUMBER:
             case InputType.TYPE_CLASS_DATETIME:
                 mode = KeyboardId.MODE_NUMBER;
@@ -559,7 +597,7 @@
                     mode = KeyboardId.MODE_WEB;
                     // If it's a browser edit field and auto correct is not ON explicitly, then
                     // disable auto correction, but keep suggestions on.
-                    if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
+                    if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
                         mInputTypeNoAutoCorrect = true;
                     }
                 } else {
@@ -567,16 +605,16 @@
                 }
 
                 // If NO_SUGGESTIONS is set, don't do prediction.
-                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
+                if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
                     mIsSettingsSuggestionStripOn = false;
                     mInputTypeNoAutoCorrect = true;
                 }
                 // If it's not multiline and the autoCorrect flag is not set, then don't correct
-                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
-                        (attribute.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
+                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
+                        (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
                     mInputTypeNoAutoCorrect = true;
                 }
-                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
+                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
                     mIsSettingsSuggestionStripOn = false;
                     mApplicationSpecifiedCompletionOn = isFullscreenMode();
                 }
@@ -585,40 +623,7 @@
                 mode = KeyboardId.MODE_TEXT;
                 break;
         }
-        inputView.closing();
-        mComposing.setLength(0);
-        mHasValidSuggestions = false;
-        mDeleteCount = 0;
-        mJustAddedAutoSpace = false;
-
-        loadSettings(attribute);
-        if (mSubtypeSwitcher.isKeyboardMode()) {
-            switcher.loadKeyboard(mode, attribute.imeOptions,
-                    mVoiceConnector.isVoiceButtonEnabled(),
-                    mVoiceConnector.isVoiceButtonOnPrimary());
-            switcher.updateShiftState();
-        }
-
-        setCandidatesViewShownInternal(isCandidateStripVisible(),
-                false /* needsInputViewShown */ );
-        // Delay updating suggestions because keyboard input view may not be shown at this point.
-        mHandler.postUpdateSuggestions();
-
-        // If the dictionary is not big enough, don't auto correct
-        mHasDictionary = mSuggest.hasMainDictionary();
-
-        updateCorrectionMode();
-
-        inputView.setPreviewEnabled(mPopupOn);
-        inputView.setProximityCorrectionEnabled(true);
-        mIsSettingsSuggestionStripOn &= (mCorrectionMode > 0 || isShowingSuggestionsStrip());
-        // If we just entered a text field, maybe it has some old text that requires correction
-        checkReCorrectionOnStart();
-        inputView.setForeground(true);
-
-        mVoiceConnector.onStartInputView(inputView.getWindowToken());
-
-        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
+        return mode;
     }
 
     private void checkReCorrectionOnStart() {
@@ -1387,7 +1392,8 @@
     }
 
     private boolean isSuggestionsRequested() {
-        return mIsSettingsSuggestionStripOn;
+        return mIsSettingsSuggestionStripOn
+                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
     }
 
     private boolean isShowingPunctuationList() {
@@ -1805,7 +1811,6 @@
         final int length = mComposing.length();
         if (!mHasValidSuggestions && length > 0) {
             final InputConnection ic = getCurrentInputConnection();
-            mHasValidSuggestions = true;
             mJustReverted = true;
             final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
             if (deleteChar) ic.deleteSurroundingText(1, 0);
@@ -1815,14 +1820,19 @@
                 toDelete--;
             }
             ic.deleteSurroundingText(toDelete, 0);
-            if (deleteChar) {
+            // Re-insert punctuation only when the deleted character was word separator and the
+            // composing text wasn't equal to the auto-corrected text.
+            if (deleteChar
+                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
+                    && !TextUtils.equals(mComposing, toTheLeft)) {
                 ic.commitText(mComposing, 1);
                 TextEntryState.acceptedTyped(mComposing);
-                if (!TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))) {
-                    ic.commitText(punctuation, 1);
-                    TextEntryState.typedCharacter(punctuation.charAt(0), true);
-                }
+                ic.commitText(punctuation, 1);
+                TextEntryState.typedCharacter(punctuation.charAt(0), true);
+                // Clear composing text
+                mComposing.setLength(0);
             } else {
+                mHasValidSuggestions = true;
                 ic.setComposingText(mComposing, 1);
                 TextEntryState.backspace();
             }
@@ -1855,9 +1865,9 @@
         return mWord.isFirstCharCapitalized();
     }
 
-    // Notify that Language has been changed and toggleLanguage will update KeyboaredID according
-    // to new Language.
-    public void onKeyboardLanguageChanged() {
+    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
+    // according to new language or mode.
+    public void onRefreshKeyboard() {
         toggleLanguage(true, true);
     }
 
@@ -1868,8 +1878,9 @@
         }
         // Reload keyboard because the current language has been changed.
         KeyboardSwitcher switcher = mKeyboardSwitcher;
-        final int mode = switcher.getKeyboardMode();
         final EditorInfo attribute = getCurrentInputEditorInfo();
+        final int mode = initializeInputAttributesAndGetMode((attribute != null)
+                ? attribute.inputType : 0);
         final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
         switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
                 mVoiceConnector.isVoiceButtonOnPrimary());
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 064a80f..5db63b7 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -134,6 +134,12 @@
         if (!showSubtypeSettings) {
             getPreferenceScreen().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));
+        }
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index b765fad..ac3401e 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -187,7 +187,7 @@
             // fallback to the default locale and mode.
             Log.w(TAG, "Couldn't get the current subtype.");
             newLocale = "en_US";
-            newMode =KEYBOARD_MODE;
+            newMode = KEYBOARD_MODE;
         } else {
             newLocale = newSubtype.getLocale();
             newMode = newSubtype.getMode();
@@ -217,8 +217,8 @@
                     mVoiceInput.cancel();
                 }
             }
-            if (languageChanged) {
-                mService.onKeyboardLanguageChanged();
+            if (modeChanged || languageChanged) {
+                mService.onRefreshKeyboard();
             }
         } else if (isVoiceMode()) {
             // If needsToShowWarningDialog is true, voice input need to show warning before