Merge "Fix a crash when MAX_WORD_LENGTH is too short."
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 78de94f..da315df 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -395,15 +395,15 @@
     <string name="subtype_mode_voice">voice</string>
     <string name="subtype_mode_cs_keyboard">Czech Keyboard</string>
     <string name="subtype_mode_da_keyboard">Danish Keyboard</string>
-    <string name="subtype_mode_de_keyboard">German Keyboard</string>
+    <string name="subtype_mode_de_keyboard">German Keyboard</string>
+    <string name="subtype_mode_en_GB_keyboard">English (United Kingdom) Keyboard</string>
     <string name="subtype_mode_en_US_keyboard">English (United States) Keyboard</string>
-    <string name="subtype_mode_en_GB_keyboard">English (Great Britain) Keyboard</string>
     <string name="subtype_mode_es_keyboard">Spanish Keyboard</string>
     <string name="subtype_mode_es_US_keyboard">Spanish (United States) Keyboard</string>
     <string name="subtype_mode_fr_keyboard">French Keyboard</string>
     <string name="subtype_mode_fr_CA_keyboard">French (Canada) Keyboard</string>
     <string name="subtype_mode_fr_CH_keyboard">French (Switzerland) Keyboard</string>
-    <string name="subtype_mode_it_keyboard">Italian Keyboard</string>
+    <string name="subtype_mode_it_keyboard">Italian Keyboard</string>
     <string name="subtype_mode_nb_keyboard">Norwegian Keyboard</string>
     <string name="subtype_mode_nl_keyboard">Dutch Keyboard</string>
     <string name="subtype_mode_ru_keyboard">Russian Keyboard</string>
@@ -411,9 +411,9 @@
     <string name="subtype_mode_sv_keyboard">Swedish Keyboard</string>
 
     <string name="subtype_mode_cs_voice">Czech Voice</string>
-    <string name="subtype_mode_de_voice">German Voice</string>
+    <string name="subtype_mode_de_voice">German Voice</string>
     <string name="subtype_mode_en_AU_voice">English (Australia) Voice</string>
-    <string name="subtype_mode_en_GB_voice">English (Great Britain) Voice</string>
+    <string name="subtype_mode_en_GB_voice">English (United Kingdom) Voice</string>
     <string name="subtype_mode_en_IN_voice">English (India) Voice</string>
     <string name="subtype_mode_en_NZ_voice">English (New Zealand) Voice</string>
     <string name="subtype_mode_en_US_voice">English (United States) Voice</string>
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 87d128f..cd42669 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -202,11 +202,19 @@
         this.mX = x + mGap / 2;
         this.mY = y;
 
-        int[] codes = style.getIntArray(a, R.styleable.Keyboard_Key_codes);
         mPreviewIcon = style.getDrawable(a, R.styleable.Keyboard_Key_iconPreview);
         Keyboard.setDefaultBounds(mPreviewIcon);
-        mPopupCharacters = style.getText(a, R.styleable.Keyboard_Key_popupCharacters);
-        mPopupResId = style.getResourceId(a, R.styleable.Keyboard_Key_popupKeyboard, 0);
+        final CharSequence popupCharacters = style.getText(a,
+                R.styleable.Keyboard_Key_popupCharacters);
+        final int popupResId = style.getResourceId(a, R.styleable.Keyboard_Key_popupKeyboard, 0);
+        // Set popup keyboard resource and characters only when both are specified.
+        if (popupResId != 0 && !TextUtils.isEmpty(popupCharacters)) {
+            mPopupResId = popupResId;
+            mPopupCharacters = popupCharacters;
+        } else {
+            mPopupResId = 0;
+            mPopupCharacters = null;
+        }
         mRepeatable = style.getBoolean(a, R.styleable.Keyboard_Key_isRepeatable, false);
         mModifier = style.getBoolean(a, R.styleable.Keyboard_Key_isModifier, false);
         mSticky = style.getBoolean(a, R.styleable.Keyboard_Key_isSticky, false);
@@ -226,16 +234,20 @@
         mManualTemporaryUpperCaseCode = style.getInt(a,
                 R.styleable.Keyboard_Key_manualTemporaryUpperCaseCode, 0);
         mOutputText = style.getText(a, R.styleable.Keyboard_Key_keyOutputText);
+        // Choose the first letter of the label as primary code if not specified.
+        final int[] codes = style.getIntArray(a, R.styleable.Keyboard_Key_codes);
+        if (codes == null && !TextUtils.isEmpty(mLabel)) {
+            mCodes = new int[] { mLabel.charAt(0) };
+        } else {
+            mCodes = codes;
+        }
+
         final Drawable shiftedIcon = style.getDrawable(a,
                 R.styleable.Keyboard_Key_shiftedIcon);
-        a.recycle();
-
         if (shiftedIcon != null)
             mKeyboard.getShiftedIcons().put(this, shiftedIcon);
 
-        if (codes == null && !TextUtils.isEmpty(mLabel))
-            codes = new int[] { mLabel.charAt(0) };
-        mCodes = codes;
+        a.recycle();
     }
 
     public Drawable getIcon() {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index c54b1b4..9842686 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -1187,9 +1187,6 @@
      * method on the base class if the subclass doesn't wish to handle the call.
      */
     protected boolean onLongPress(Key popupKey) {
-        // TODO if popupKey.popupCharacters has only one letter, send it as key without opening
-        // mini keyboard.
-
         if (popupKey.mPopupResId == 0)
             return false;
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 702731e..3089153 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -645,13 +645,18 @@
     }
 
     private void checkReCorrectionOnStart() {
-        if (mReCorrectionEnabled && isSuggestionShown() && isPredictionOn()) {
+        if (!mReCorrectionEnabled) return;
+
+        final InputConnection ic = getCurrentInputConnection();
+        if (ic == null) return;
+        // There could be a pending composing span.  Clean it up first.
+        ic.finishComposingText();
+
+        if (isSuggestionShown() && isPredictionOn()) {
             // First get the cursor position. This is required by setOldSuggestions(), so that
             // it can pass the correct range to setComposingRegion(). At this point, we don't
             // have valid values for mLastSelectionStart/Stop because onUpdateSelection() has
             // not been called yet.
-            InputConnection ic = getCurrentInputConnection();
-            if (ic == null) return;
             ExtractedTextRequest etr = new ExtractedTextRequest();
             etr.token = 0; // anything is fine here
             ExtractedText et = ic.getExtractedText(etr, 0);
@@ -677,8 +682,7 @@
         mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
 
         KeyboardView inputView = mKeyboardSwitcher.getInputView();
-        if (inputView != null)
-            inputView.closing();
+        if (inputView != null) inputView.closing();
         if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
         if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
     }
@@ -687,8 +691,7 @@
     public void onFinishInputView(boolean finishingInput) {
         super.onFinishInputView(finishingInput);
         KeyboardView inputView = mKeyboardSwitcher.getInputView();
-        if (inputView != null)
-            inputView.setForeground(false);
+        if (inputView != null) inputView.setForeground(false);
         // Remove pending messages related to update suggestions
         mHandler.cancelUpdateSuggestions();
         mHandler.cancelUpdateOldSuggestions();