Merge "Cleanup ExpandableBinaryDictionary."
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 3e3bedf..7d86dbd 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -157,13 +157,6 @@
                 android:summary="@string/include_other_imes_in_language_switch_list_summary"
                 android:persistent="true"
                 android:defaultValue="false" />
-            <!-- Values for popup dismiss delay are added programmatically -->
-            <CheckBoxPreference
-                android:key="pref_sliding_key_input_preview"
-                android:title="@string/sliding_key_input_preview"
-                android:summary="@string/sliding_key_input_preview_summary"
-                android:persistent="true"
-                android:defaultValue="true" />
             <ListPreference
                 android:key="pref_keyboard_layout_20110916"
                 android:title="@string/keyboard_color_scheme"
@@ -180,12 +173,6 @@
                 android:key="pref_key_preview_popup_dismiss_delay"
                 android:title="@string/key_preview_popup_dismiss_delay" />
             <com.android.inputmethod.latin.settings.SeekBarDialogPreference
-                android:key="pref_key_longpress_timeout"
-                android:title="@string/prefs_key_longpress_timeout_settings"
-                latin:minValue="@integer/config_min_longpress_timeout"
-                latin:maxValue="@integer/config_max_longpress_timeout"
-                latin:stepValue="@integer/config_longpress_timeout_step" />
-            <com.android.inputmethod.latin.settings.SeekBarDialogPreference
                 android:key="pref_vibration_duration_settings"
                 android:title="@string/prefs_keypress_vibration_duration_settings"
                 latin:maxValue="@integer/config_max_vibration_duration" />
diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml
index bb6a641..c333b07 100644
--- a/java/res/xml/prefs_for_debug.xml
+++ b/java/res/xml/prefs_for_debug.xml
@@ -41,6 +41,18 @@
         android:title="@string/prefs_usability_study_mode"
         android:persistent="true"
         android:defaultValue="false" />
+    <CheckBoxPreference
+        android:key="pref_sliding_key_input_preview"
+        android:title="@string/sliding_key_input_preview"
+        android:summary="@string/sliding_key_input_preview_summary"
+        android:persistent="true"
+        android:defaultValue="true" />
+    <com.android.inputmethod.latin.settings.SeekBarDialogPreference
+        android:key="pref_key_longpress_timeout"
+        android:title="@string/prefs_key_longpress_timeout_settings"
+        latin:minValue="@integer/config_min_longpress_timeout"
+        latin:maxValue="@integer/config_max_longpress_timeout"
+        latin:stepValue="@integer/config_longpress_timeout_step" />
     <com.android.inputmethod.latin.settings.SeekBarDialogPreference
         android:key="pref_key_preview_show_up_start_scale"
         android:title="@string/prefs_key_popup_show_up_start_scale_settings"
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index a80c3fe..18b3a60 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -28,6 +28,12 @@
     private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod(
             InputMethodManager.class, "switchToNextInputMethod", IBinder.class, Boolean.TYPE);
 
+    // Note that InputMethodManager.shouldOfferSwitchingToNextInputMethod() has been introduced
+    // in API level 19 (Build.VERSION_CODES.KITKAT).
+    private static final Method METHOD_shouldOfferSwitchingToNextInputMethod =
+            CompatUtils.getMethod(InputMethodManager.class,
+                    "shouldOfferSwitchingToNextInputMethod", IBinder.class);
+
     public final InputMethodManager mImm;
 
     public InputMethodManagerCompatWrapper(final Context context) {
@@ -38,4 +44,9 @@
         return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */,
                 METHOD_switchToNextInputMethod, token, onlyCurrentIme);
     }
+
+    public boolean shouldOfferSwitchingToNextInputMethod(final IBinder token) {
+        return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */,
+                METHOD_shouldOfferSwitchingToNextInputMethod, token);
+    }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index dcf7f74..0235fde 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -123,7 +123,7 @@
         builder.setOptions(
                 mSubtypeSwitcher.isShortcutImeEnabled(),
                 settingsValues.mShowsVoiceInputKey,
-                settingsValues.isLanguageSwitchKeyEnabled());
+                mLatinIME.shouldSwitchToOtherInputMethods());
         mKeyboardLayoutSet = builder.build();
         mCurrentSettingsValues = settingsValues;
         try {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index a77cedc..f1b1b8d 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1229,7 +1229,7 @@
     // TODO: Revise the language switch key behavior to make it much smarter and more reasonable.
     public void switchToNextSubtype() {
         final IBinder token = getWindow().getWindow().getAttributes().token;
-        if (mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList) {
+        if (shouldSwitchToOtherInputMethods()) {
             mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */);
             return;
         }
@@ -1799,4 +1799,28 @@
         p.println(settingsValues.dump());
         // TODO: Dump all settings values
     }
+
+    public boolean shouldSwitchToOtherInputMethods() {
+        // TODO: Revisit here to reorganize the settings. Probably we can/should use different
+        // strategy once the implementation of
+        // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is defined well.
+        final boolean fallbackValue = mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList;
+        final IBinder token = getWindow().getWindow().getAttributes().token;
+        if (token == null) {
+            return fallbackValue;
+        }
+        return mRichImm.shouldOfferSwitchingToNextInputMethod(token, fallbackValue);
+    }
+
+    public boolean shouldShowLanguageSwitchKey() {
+        // TODO: Revisit here to reorganize the settings. Probably we can/should use different
+        // strategy once the implementation of
+        // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is defined well.
+        final boolean fallbackValue = mSettings.getCurrent().isLanguageSwitchKeyEnabled();
+        final IBinder token = getWindow().getWindow().getAttributes().token;
+        if (token == null) {
+            return fallbackValue;
+        }
+        return mRichImm.shouldOfferSwitchingToNextInputMethod(token, fallbackValue);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index 630a036..2b0be54 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.os.Build;
 import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.util.Log;
@@ -406,4 +407,15 @@
         mSubtypeListCacheWithoutImplicitlySelectedSubtypes.clear();
         mInputMethodInfoCache.clear();
     }
+
+    public boolean shouldOfferSwitchingToNextInputMethod(final IBinder binder,
+            boolean defaultValue) {
+        // Use the default value instead on Jelly Bean MR2 and previous where
+        // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} isn't yet available
+        // and on KitKat where the API is still just a stub to return true always.
+        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+            return defaultValue;
+        }
+        return mImmWrapper.shouldOfferSwitchingToNextInputMethod(binder);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index 11d3692..c4c1234 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -55,6 +55,8 @@
     private static final String PREF_DUMP_USER_DICT = "dump_user_dict";
     private static final String PREF_DUMP_USER_HISTORY_DICT = "dump_user_history_dict";
     private static final String PREF_DUMP_PERSONALIZATION_DICT = "dump_personalization_dict";
+    public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview";
+    public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
 
     private static final boolean SHOW_STATISTICS_LOGGING = false;
 
@@ -110,6 +112,7 @@
         findPreference(PREF_DUMP_PERSONALIZATION_DICT).setOnPreferenceClickListener(
                 dictDumpPrefClickListener);
         final Resources res = getResources();
+        setupKeyLongpressTimeoutSettings(prefs, res);
         setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_SHOW_UP_DURATION,
                 res.getInteger(R.integer.config_key_preview_show_up_duration));
         setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_DISMISS_DURATION,
@@ -200,6 +203,44 @@
         }
     }
 
+    private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp,
+            final Resources res) {
+        final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
+                PREF_KEY_LONGPRESS_TIMEOUT);
+        if (pref == null) {
+            return;
+        }
+        pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+            @Override
+            public void writeValue(final int value, final String key) {
+                sp.edit().putInt(key, value).apply();
+            }
+
+            @Override
+            public void writeDefaultValue(final String key) {
+                sp.edit().remove(key).apply();
+            }
+
+            @Override
+            public int readValue(final String key) {
+                return Settings.readKeyLongpressTimeout(sp, res);
+            }
+
+            @Override
+            public int readDefaultValue(final String key) {
+                return Settings.readDefaultKeyLongpressTimeout(res);
+            }
+
+            @Override
+            public String getValueText(final int value) {
+                return res.getString(R.string.abbreviation_unit_milliseconds, value);
+            }
+
+            @Override
+            public void feedbackValue(final int value) {}
+        });
+    }
+
     private void setupKeyPreviewAnimationScale(final SharedPreferences sp, final Resources res,
             final String prefKey, final float defaultValue) {
         final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey);
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 353b746..a3aae8c 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -72,8 +72,6 @@
     public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction";
     public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings";
     public static final String PREF_GESTURE_INPUT = "gesture_input";
-    public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview";
-    public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
     public static final String PREF_VIBRATION_DURATION_SETTINGS =
             "pref_vibration_duration_settings";
     public static final String PREF_KEYPRESS_SOUND_VOLUME =
@@ -196,7 +194,7 @@
     // Accessed from the settings interface, hence public
     public static boolean readKeypressSoundEnabled(final SharedPreferences prefs,
             final Resources res) {
-        return prefs.getBoolean(Settings.PREF_SOUND_ON,
+        return prefs.getBoolean(PREF_SOUND_ON,
                 res.getBoolean(R.bool.config_default_sound_enabled));
     }
 
@@ -216,7 +214,7 @@
 
     public static boolean readBlockPotentiallyOffensive(final SharedPreferences prefs,
             final Resources res) {
-        return prefs.getBoolean(Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE,
+        return prefs.getBoolean(PREF_BLOCK_POTENTIALLY_OFFENSIVE,
                 res.getBoolean(R.bool.config_block_potentially_offensive));
     }
 
@@ -227,12 +225,12 @@
     public static boolean readGestureInputEnabled(final SharedPreferences prefs,
             final Resources res) {
         return readFromBuildConfigIfGestureInputEnabled(res)
-                && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true);
+                && prefs.getBoolean(PREF_GESTURE_INPUT, true);
     }
 
     public static boolean readPhraseGestureEnabled(final SharedPreferences prefs,
             final Resources res) {
-        return prefs.getBoolean(Settings.PREF_PHRASE_GESTURE_ENABLED,
+        return prefs.getBoolean(PREF_PHRASE_GESTURE_ENABLED,
                 res.getBoolean(R.bool.config_default_phrase_gesture_enabled));
     }
 
@@ -278,7 +276,7 @@
 
     public static void writePrefAdditionalSubtypes(final SharedPreferences prefs,
             final String prefSubtypes) {
-        prefs.edit().putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply();
+        prefs.edit().putString(PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply();
     }
 
     public static float readKeypressSoundVolume(final SharedPreferences prefs,
@@ -301,7 +299,7 @@
     public static int readKeyLongpressTimeout(final SharedPreferences prefs,
             final Resources res) {
         final int milliseconds = prefs.getInt(
-                PREF_KEY_LONGPRESS_TIMEOUT, UNDEFINED_PREFERENCE_VALUE_INT);
+                DebugSettings.PREF_KEY_LONGPRESS_TIMEOUT, UNDEFINED_PREFERENCE_VALUE_INT);
         return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds
                 : readDefaultKeyLongpressTimeout(res);
     }
@@ -354,18 +352,18 @@
         if (!enableSetupWizardByConfig) {
             return false;
         }
-        if (!prefs.contains(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
+        if (!prefs.contains(PREF_SHOW_SETUP_WIZARD_ICON)) {
             final ApplicationInfo appInfo = context.getApplicationInfo();
             final boolean isApplicationInSystemImage =
                     (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
             // Default value
             return !isApplicationInSystemImage;
         }
-        return prefs.getBoolean(Settings.PREF_SHOW_SETUP_WIZARD_ICON, false);
+        return prefs.getBoolean(PREF_SHOW_SETUP_WIZARD_ICON, false);
     }
 
     public static boolean isInternal(final SharedPreferences prefs) {
-        return prefs.getBoolean(Settings.PREF_KEY_IS_INTERNAL, false);
+        return prefs.getBoolean(PREF_KEY_IS_INTERNAL, false);
     }
 
     public void writeLastUsedPersonalizationToken(byte[] token) {
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index bb5547f..22cbd20 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -228,7 +228,6 @@
 
         AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
 
-        setupKeyLongpressTimeoutSettings(prefs, res);
         setupKeypressVibrationDurationSettings(prefs, res);
         setupKeypressSoundVolumeSettings(prefs, res);
         refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res);
@@ -368,44 +367,6 @@
         });
     }
 
-    private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp,
-            final Resources res) {
-        final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
-                Settings.PREF_KEY_LONGPRESS_TIMEOUT);
-        if (pref == null) {
-            return;
-        }
-        pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
-            @Override
-            public void writeValue(final int value, final String key) {
-                sp.edit().putInt(key, value).apply();
-            }
-
-            @Override
-            public void writeDefaultValue(final String key) {
-                sp.edit().remove(key).apply();
-            }
-
-            @Override
-            public int readValue(final String key) {
-                return Settings.readKeyLongpressTimeout(sp, res);
-            }
-
-            @Override
-            public int readDefaultValue(final String key) {
-                return Settings.readDefaultKeyLongpressTimeout(res);
-            }
-
-            @Override
-            public String getValueText(final int value) {
-                return res.getString(R.string.abbreviation_unit_milliseconds, value);
-            }
-
-            @Override
-            public void feedbackValue(final int value) {}
-        });
-    }
-
     private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) {
         final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
                 Settings.PREF_KEYPRESS_SOUND_VOLUME);
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index d47a61e..dde50cc 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -119,7 +119,7 @@
         mSoundOn = Settings.readKeypressSoundEnabled(prefs, res);
         mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res);
         mSlidingKeyInputPreviewEnabled = prefs.getBoolean(
-                Settings.PREF_SLIDING_KEY_INPUT_PREVIEW, true);
+                DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true);
         mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res);
         final String autoCorrectionThresholdRawValue = prefs.getString(
                 Settings.PREF_AUTO_CORRECTION_THRESHOLD,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index a104baa..5a325ea 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -74,7 +74,13 @@
             int rowStartIndex = fromIndex;
             final int size = Math.min(suggestedWords.size(), SuggestedWords.MAX_SUGGESTIONS);
             while (index < size) {
-                final String word = suggestedWords.getLabel(index);
+                final String word;
+                if (isIndexSubjectToAutoCorrection(suggestedWords, index)) {
+                    // INDEX_OF_AUTO_CORRECTION and INDEX_OF_TYPED_WORD got swapped.
+                    word = suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD);
+                } else {
+                    word = suggestedWords.getLabel(index);
+                }
                 // TODO: Should take care of text x-scaling.
                 mWidths[index] = (int)(TypefaceUtils.getStringWidth(word, paint) + padding);
                 final int numColumn = index - rowStartIndex + 1;
@@ -172,6 +178,11 @@
         }
     }
 
+    private static boolean isIndexSubjectToAutoCorrection(final SuggestedWords suggestedWords,
+            final int index) {
+        return suggestedWords.mWillAutoCorrect && index == SuggestedWords.INDEX_OF_AUTO_CORRECTION;
+    }
+
     public static final class Builder extends KeyboardBuilder<MoreSuggestionsParam> {
         private final MoreSuggestionsView mPaneView;
         private SuggestedWords mSuggestedWords;
@@ -189,7 +200,6 @@
             final int xmlId = R.xml.kbd_suggestions_pane_template;
             load(xmlId, parentKeyboard.mId);
             mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
-
             mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight);
             final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow,
                     mPaneView.newLabelPaint(null /* key */), mResources);
@@ -206,8 +216,16 @@
                 final int x = params.getX(index);
                 final int y = params.getY(index);
                 final int width = params.getWidth(index);
-                final String word = mSuggestedWords.getLabel(index);
-                final String info = mSuggestedWords.getDebugString(index);
+                final String word;
+                final String info;
+                if (isIndexSubjectToAutoCorrection(mSuggestedWords, index)) {
+                    // INDEX_OF_AUTO_CORRECTION and INDEX_OF_TYPED_WORD got swapped.
+                    word = mSuggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD);
+                    info = mSuggestedWords.getDebugString(SuggestedWords.INDEX_OF_TYPED_WORD);
+                } else {
+                    word = mSuggestedWords.getLabel(index);
+                    info = mSuggestedWords.getDebugString(index);
+                }
                 final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE;
                 final Key key = new Key(word, KeyboardIconsSet.ICON_UNDEFINED,
                         indexInMoreSuggestions, null /* outputText */, info, 0 /* labelFlags */,
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 3becc79..2fe2bd8 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -330,9 +330,6 @@
 #define MAX_PROBABILITY 255
 #define MAX_BIGRAM_ENCODED_PROBABILITY 15
 
-// Assuming locale strings such as en_US, sr-Latn etc.
-#define MAX_LOCALE_STRING_LENGTH 10
-
 // Max value for length, distance and probability which are used in weighting
 // TODO: Remove
 #define MAX_VALUE_FOR_WEIGHTING 10000000
diff --git a/native/jni/src/suggest/core/layout/proximity_info.h b/native/jni/src/suggest/core/layout/proximity_info.h
index 56711d1..d4e4537 100644
--- a/native/jni/src/suggest/core/layout/proximity_info.h
+++ b/native/jni/src/suggest/core/layout/proximity_info.h
@@ -103,6 +103,8 @@
     const int KEYBOARD_HEIGHT;
     const float KEYBOARD_HYPOTENUSE;
     const bool HAS_TOUCH_POSITION_CORRECTION_DATA;
+    // Assuming locale strings such as en_US, sr-Latn etc.
+    static const int MAX_LOCALE_STRING_LENGTH = 10;
     char mLocaleStr[MAX_LOCALE_STRING_LENGTH];
     int *mProximityCharsArray;
     int mKeyXCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD];