Merge "Show usability study mode for research purposes"
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 7341896..7e7f2b8 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -36,6 +36,7 @@
 import com.android.inputmethod.latin.LocaleUtils;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.Settings;
+import com.android.inputmethod.latin.SettingsValues;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.Utils;
 
@@ -132,7 +133,7 @@
         }
     }
 
-    public void loadKeyboard(EditorInfo editorInfo, Settings.Values settingsValues) {
+    public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) {
         try {
             mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues);
             mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues);
@@ -163,11 +164,10 @@
         mKeyboardView.setKeyboard(keyboard);
         mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
         mCurrentId = keyboard.mId;
-        mState.onSetKeyboard(isAlphabetMode());
         updateShiftLockState(keyboard);
         mKeyboardView.setKeyPreviewPopupEnabled(
-                Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources),
-                Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
+                SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources),
+                SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
         final boolean localeChanged = (oldKeyboard == null)
                 || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
         mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
@@ -226,7 +226,7 @@
     }
 
     private KeyboardId getKeyboardId(EditorInfo editorInfo, final boolean isSymbols,
-            final boolean isShift, Settings.Values settingsValues) {
+            final boolean isShift, SettingsValues settingsValues) {
         final int mode = Utils.getKeyboardMode(editorInfo);
         final int xmlId;
         switch (mode) {
@@ -361,15 +361,7 @@
         if (DEBUG_STATE) {
             Log.d(TAG, "toggleShift: " + mState);
         }
-        if (isAlphabetMode()) {
-            setShifted(mState.isShiftedOrShiftLocked() ? UNSHIFT : MANUAL_SHIFT);
-        } else {
-            if (isSymbolShifted()) {
-                setSymbolsKeyboard();
-            } else {
-                setSymbolsShiftedKeyboard();
-            }
-        }
+        mState.onToggleShift(isAlphabetMode(), isSymbolShifted());
     }
 
     /**
@@ -379,31 +371,17 @@
         if (DEBUG_STATE) {
             Log.d(TAG, "toggleCapsLock: " + mState);
         }
-        if (isAlphabetMode()) {
-            if (mState.isShiftLocked()) {
-                setShiftLocked(false);
-                // TODO: Remove this.
-                // Shift key is long pressed while caps lock state, we will toggle back to normal
-                // state. And mark as if shift key is released.
-                mState.onReleaseCapsLock();
-            } else {
-                setShiftLocked(true);
-            }
-        }
+        mState.onToggleCapsLock(isAlphabetMode());
     }
 
     /**
-     * Toggle keyboard mode triggered by user touch event.
+     * Toggle between alphabet and symbols modes triggered by user touch event.
      */
-    public void toggleKeyboardMode() {
+    public void toggleAlphabetAndSymbols() {
         if (DEBUG_STATE) {
-            Log.d(TAG, "toggleKeyboardMode: " + mState);
+            Log.d(TAG, "toggleAlphabetAndSymbols: " + mState);
         }
-        if (isAlphabetMode()) {
-            setSymbolsKeyboard();
-        } else {
-            setAlphabetKeyboard();
-        }
+        mState.onToggleAlphabetAndSymbols(isAlphabetMode());
     }
 
     /**
@@ -463,7 +441,6 @@
     // Implements {@link KeyboardState.SwitchActions}.
     @Override
     public void setSymbolsKeyboard() {
-        mState.onSaveShiftLockState();
         setKeyboard(getKeyboard(mSymbolsKeyboardId));
     }
 
@@ -471,7 +448,6 @@
     @Override
     public void setAlphabetKeyboard() {
         setKeyboard(getKeyboard(mMainKeyboardId));
-        mState.onRestoreShiftLockState();
     }
 
     // TODO: Remove this method
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 95c9162..c952ea6 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -105,12 +105,12 @@
                     + " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
         }
         if (!state.mIsValid || state.mIsAlphabetMode) {
-            mSwitchActions.setAlphabetKeyboard();
+            setAlphabetKeyboard();
         } else {
             if (state.mIsShifted) {
-                mSwitchActions.setSymbolsShiftedKeyboard();
+                setSymbolsShiftedKeyboard();
             } else {
-                mSwitchActions.setSymbolsKeyboard();
+                setSymbolsKeyboard();
             }
         }
 
@@ -126,11 +126,6 @@
         }
     }
 
-    // TODO: Get rid of this method
-    public void onSetKeyboard(boolean isAlphabetMode) {
-        mSwitchState = isAlphabetMode ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
-    }
-
     public boolean isShiftLocked() {
         return mKeyboardShiftState.isShiftLocked();
     }
@@ -172,32 +167,36 @@
 
     private void toggleAlphabetAndSymbols(boolean isAlphabetMode) {
         if (isAlphabetMode) {
-            mSwitchActions.setSymbolsKeyboard();
+            setSymbolsKeyboard();
         } else {
-            mSwitchActions.setAlphabetKeyboard();
+            setAlphabetKeyboard();
         }
     }
 
     private void toggleShiftInSymbols(boolean isSymbolShifted) {
         if (isSymbolShifted) {
-            mSwitchActions.setSymbolsKeyboard();
+            setSymbolsKeyboard();
         } else {
-            mSwitchActions.setSymbolsShiftedKeyboard();
+            setSymbolsShiftedKeyboard();
         }
     }
 
-    public void onRestoreShiftLockState() {
+    private void setAlphabetKeyboard() {
+        mSwitchActions.setAlphabetKeyboard();
+        mSwitchState = SWITCH_STATE_ALPHA;
         mSwitchActions.setShiftLocked(mPrevMainKeyboardWasShiftLocked);
         mPrevMainKeyboardWasShiftLocked = false;
     }
 
-    public void onSaveShiftLockState() {
+    private void setSymbolsKeyboard() {
         mPrevMainKeyboardWasShiftLocked = isShiftLocked();
+        mSwitchActions.setSymbolsKeyboard();
+        mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
     }
 
-    // TODO: Remove this method.
-    public void onReleaseCapsLock() {
-        mShiftKeyState.onRelease();
+    private void setSymbolsShiftedKeyboard() {
+        mSwitchActions.setSymbolsShiftedKeyboard();
+        mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
     }
 
     // TODO: Get rid of isAlphabetMode argument.
@@ -384,7 +383,7 @@
             }
             // Snap back to alpha keyboard mode immediately if user types a quote character.
             if (isLayoutSwitchBackCharacter(code)) {
-                mSwitchActions.setAlphabetKeyboard();
+                setAlphabetKeyboard();
             }
             break;
         case SWITCH_STATE_SYMBOL:
@@ -392,12 +391,41 @@
             // Snap back to alpha keyboard mode if user types one or more non-space/enter
             // characters followed by a space/enter or a quote character.
             if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
-                mSwitchActions.setAlphabetKeyboard();
+                setAlphabetKeyboard();
             }
             break;
         }
     }
 
+    // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+    public void onToggleShift(boolean isAlphabetMode, boolean isSymbolShifted) {
+        if (isAlphabetMode) {
+            mSwitchActions.setShifted(
+                    isShiftedOrShiftLocked() ? SwitchActions.UNSHIFT : SwitchActions.MANUAL_SHIFT);
+        } else {
+            toggleShiftInSymbols(isSymbolShifted);
+        }
+    }
+
+    // TODO: Get rid of isAlphabetMode arguments.
+    public void onToggleCapsLock(boolean isAlphabetMode) {
+        if (isAlphabetMode) {
+            if (isShiftLocked()) {
+                mSwitchActions.setShiftLocked(false);
+                // Shift key is long pressed while caps lock state, we will toggle back to normal
+                // state. And mark as if shift key is released.
+                mShiftKeyState.onRelease();
+            } else {
+                mSwitchActions.setShiftLocked(true);
+            }
+        }
+    }
+
+    // TODO: Get rid of isAlphabetMode arguments.
+    public void onToggleAlphabetAndSymbols(boolean isAlphabetMode) {
+        toggleAlphabetAndSymbols(isAlphabetMode);
+    }
+
     private static String switchStateToString(int switchState) {
         switch (switchState) {
         case SWITCH_STATE_ALPHA: return "ALPHA";
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5ee69d1..602de92 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -174,7 +174,7 @@
     // Current space state of the input method. This can be any of the above constants.
     private int mSpaceState;
 
-    private Settings.Values mSettingsValues;
+    private SettingsValues mSettingsValues;
 
     private View mExtractArea;
     private View mKeyPreviewBackingView;
@@ -548,7 +548,7 @@
     /* package */ void loadSettings() {
         if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
         if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
-        mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
+        mSettingsValues = new SettingsValues(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
         resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
         updateSoundEffectVolume();
         updateKeypressVibrationDuration();
@@ -1335,7 +1335,7 @@
         case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
             // Symbol key is handled in onPress() when device has distinct multi-touch panel.
             if (!distinctMultiTouch) {
-                switcher.toggleKeyboardMode();
+                switcher.toggleAlphabetAndSymbols();
             }
             break;
         case Keyboard.CODE_CANCEL:
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 0985d45..9f2f317 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -38,7 +38,6 @@
 import android.text.method.LinkMovementMethod;
 import android.util.Log;
 import android.view.View;
-import android.view.inputmethod.EditorInfo;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
@@ -46,12 +45,10 @@
 import com.android.inputmethod.compat.CompatUtils;
 import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
-import com.android.inputmethod.compat.InputTypeCompatUtils;
 import com.android.inputmethod.compat.VibratorCompatWrapper;
 import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethodcommon.InputMethodSettingsActivity;
 
-import java.util.Arrays;
 import java.util.Locale;
 
 public class Settings extends InputMethodSettingsActivity
@@ -100,219 +97,6 @@
     // Dialog ids
     private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
 
-    public static class Values {
-        // From resources:
-        public final int mDelayUpdateOldSuggestions;
-        public final String mWordSeparators;
-        public final String mMagicSpaceStrippers;
-        public final String mMagicSpaceSwappers;
-        public final String mSuggestPuncs;
-        public final SuggestedWords mSuggestPuncList;
-        private final String mSymbolsExcludedFromWordSeparators;
-        public final CharSequence mHintToSaveText;
-
-        // From preferences:
-        public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn)
-        public final boolean mVibrateOn;
-        public final boolean mKeyPreviewPopupOn;
-        public final int mKeyPreviewPopupDismissDelay;
-        public final boolean mAutoCap;
-        public final boolean mAutoCorrectEnabled;
-        public final double mAutoCorrectionThreshold;
-        // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
-        public final boolean mBigramSuggestionEnabled;
-        // Prediction: use bigrams to predict the next word when there is no input for it yet
-        public final boolean mBigramPredictionEnabled;
-        public final boolean mUseContactsDict;
-        public final boolean mEnableSuggestionSpanInsertion;
-
-        private final boolean mShowSettingsKey;
-        private final boolean mVoiceKeyEnabled;
-        private final boolean mVoiceKeyOnMain;
-
-        public Values(final SharedPreferences prefs, final Context context,
-                final String localeStr) {
-            final Resources res = context.getResources();
-            final Locale savedLocale;
-            if (null != localeStr) {
-                final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
-                savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
-            } else {
-                savedLocale = null;
-            }
-
-            // Get the resources
-            mDelayUpdateOldSuggestions = res.getInteger(
-                    R.integer.config_delay_update_old_suggestions);
-            mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
-            mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
-            String wordSeparators = mMagicSpaceStrippers + mMagicSpaceSwappers
-                    + res.getString(R.string.magic_space_promoting_symbols);
-            final String symbolsExcludedFromWordSeparators =
-                    res.getString(R.string.symbols_excluded_from_word_separators);
-            for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
-                wordSeparators = wordSeparators.replace(
-                        symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
-            }
-            mSymbolsExcludedFromWordSeparators = symbolsExcludedFromWordSeparators;
-            mWordSeparators = wordSeparators;
-            mSuggestPuncs = res.getString(R.string.suggested_punctuations);
-            // TODO: it would be nice not to recreate this each time we change the configuration
-            mSuggestPuncList = createSuggestPuncList(mSuggestPuncs);
-            mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
-
-            // Get the settings preferences
-            final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator();
-            mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON,
-                    res.getBoolean(R.bool.config_default_vibration_enabled));
-            mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
-                    res.getBoolean(R.bool.config_default_sound_enabled));
-            mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res);
-            mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res);
-            mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
-            mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res);
-            mBigramSuggestionEnabled = mAutoCorrectEnabled
-                    && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
-            mBigramPredictionEnabled = mBigramSuggestionEnabled
-                    && isBigramPredictionEnabled(prefs, res);
-            mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res);
-            mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
-            mEnableSuggestionSpanInsertion =
-                    prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
-            final boolean defaultShowSettingsKey = res.getBoolean(
-                    R.bool.config_default_show_settings_key);
-            mShowSettingsKey = isShowSettingsKeyOption(res)
-                    ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey)
-                    : defaultShowSettingsKey;
-            final String voiceModeMain = res.getString(R.string.voice_mode_main);
-            final String voiceModeOff = res.getString(R.string.voice_mode_off);
-            final String voiceMode = prefs.getString(PREF_VOICE_SETTINGS_KEY, voiceModeMain);
-            mVoiceKeyEnabled = voiceMode != null && !voiceMode.equals(voiceModeOff);
-            mVoiceKeyOnMain = voiceMode != null && voiceMode.equals(voiceModeMain);
-
-            LocaleUtils.setSystemLocale(res, savedLocale);
-        }
-
-        public boolean isSuggestedPunctuation(int code) {
-            return mSuggestPuncs.contains(String.valueOf((char)code));
-        }
-
-        public boolean isWordSeparator(int code) {
-            return mWordSeparators.contains(String.valueOf((char)code));
-        }
-
-        public boolean isSymbolExcludedFromWordSeparators(int code) {
-            return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
-        }
-
-        public boolean isMagicSpaceStripper(int code) {
-            return mMagicSpaceStrippers.contains(String.valueOf((char)code));
-        }
-
-        public boolean isMagicSpaceSwapper(int code) {
-            return mMagicSpaceSwappers.contains(String.valueOf((char)code));
-        }
-
-        private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) {
-            final String currentAutoCorrectionSetting = sp.getString(
-                    Settings.PREF_AUTO_CORRECTION_THRESHOLD,
-                    resources.getString(R.string.auto_correction_threshold_mode_index_modest));
-            final String autoCorrectionOff = resources.getString(
-                    R.string.auto_correction_threshold_mode_index_off);
-            return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
-        }
-
-        // Public to access from KeyboardSwitcher. Should it have access to some
-        // process-global instance instead?
-        public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) {
-            final boolean showPopupOption = resources.getBoolean(
-                    R.bool.config_enable_show_popup_on_keypress_option);
-            if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview);
-            return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON,
-                    resources.getBoolean(R.bool.config_default_popup_preview));
-        }
-
-        // Likewise
-        public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp,
-                Resources resources) {
-            return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
-                    Integer.toString(resources.getInteger(R.integer.config_delay_after_preview))));
-        }
-
-        private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources,
-                boolean autoCorrectEnabled) {
-            final boolean showBigramSuggestionsOption = resources.getBoolean(
-                    R.bool.config_enable_bigram_suggestions_option);
-            if (!showBigramSuggestionsOption) {
-                return autoCorrectEnabled;
-            }
-            return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean(
-                    R.bool.config_default_bigram_suggestions));
-        }
-
-        private static boolean isBigramPredictionEnabled(SharedPreferences sp,
-                Resources resources) {
-            return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean(
-                    R.bool.config_default_bigram_prediction));
-        }
-
-        private static double getAutoCorrectionThreshold(SharedPreferences sp,
-                Resources resources) {
-            final String currentAutoCorrectionSetting = sp.getString(
-                    Settings.PREF_AUTO_CORRECTION_THRESHOLD,
-                    resources.getString(R.string.auto_correction_threshold_mode_index_modest));
-            final String[] autoCorrectionThresholdValues = resources.getStringArray(
-                    R.array.auto_correction_threshold_values);
-            // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
-            double autoCorrectionThreshold = Double.MAX_VALUE;
-            try {
-                final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
-                if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
-                    autoCorrectionThreshold = Double.parseDouble(
-                            autoCorrectionThresholdValues[arrayIndex]);
-                }
-            } catch (NumberFormatException e) {
-                // Whenever the threshold settings are correct, never come here.
-                autoCorrectionThreshold = Double.MAX_VALUE;
-                Log.w(TAG, "Cannot load auto correction threshold setting."
-                        + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
-                        + ", autoCorrectionThresholdValues: "
-                        + Arrays.toString(autoCorrectionThresholdValues));
-            }
-            return autoCorrectionThreshold;
-        }
-
-        private static SuggestedWords createSuggestPuncList(final String puncs) {
-            SuggestedWords.Builder builder = new SuggestedWords.Builder();
-            if (puncs != null) {
-                for (int i = 0; i < puncs.length(); i++) {
-                    builder.addWord(puncs.subSequence(i, i + 1));
-                }
-            }
-            return builder.setIsPunctuationSuggestions().build();
-        }
-
-        public static boolean isShowSettingsKeyOption(final Resources resources) {
-            return resources.getBoolean(R.bool.config_enable_show_settings_key_option);
-
-        }
-
-        public boolean isSettingsKeyEnabled() {
-            return mShowSettingsKey;
-        }
-
-        public boolean isVoiceKeyEnabled(EditorInfo editorInfo) {
-            final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
-            final int inputType = (editorInfo != null) ? editorInfo.inputType : 0;
-            return shortcutImeEnabled && mVoiceKeyEnabled
-                    && !InputTypeCompatUtils.isPasswordInputType(inputType);
-        }
-
-        public boolean isVoiceKeyOnMain() {
-            return mVoiceKeyOnMain;
-        }
-    }
-
     private PreferenceScreen mInputLanguageSelection;
     private PreferenceScreen mKeypressVibrationDurationSettingsPref;
     private PreferenceScreen mKeypressSoundVolumeSettingsPref;
@@ -399,7 +183,7 @@
         final PreferenceGroup miscSettings =
                 (PreferenceGroup) findPreference(PREF_MISC_SETTINGS_KEY);
 
-        if (!Values.isShowSettingsKeyOption(res)) {
+        if (!SettingsValues.isShowSettingsKeyOption(res)) {
             generalSettings.removePreference(mShowSettingsKeyPreference);
         }
 
@@ -446,7 +230,8 @@
         if (null == mKeyPreviewPopupDismissDelay.getValue()) {
             mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
         }
-        mKeyPreviewPopupDismissDelay.setEnabled(Values.isKeyPreviewPopupEnabled(prefs, res));
+        mKeyPreviewPopupDismissDelay.setEnabled(
+                SettingsValues.isKeyPreviewPopupEnabled(prefs, res));
 
         final PreferenceScreen dictionaryLink =
                 (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY);
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
new file mode 100644
index 0000000..4aa683a
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2011 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
+ *
+ * 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. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.inputmethod.compat.InputTypeCompatUtils;
+import com.android.inputmethod.compat.VibratorCompatWrapper;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+public class SettingsValues {
+    private static final String TAG = SettingsValues.class.getSimpleName();
+
+    // From resources:
+    public final int mDelayUpdateOldSuggestions;
+    public final String mWordSeparators;
+    public final String mMagicSpaceStrippers;
+    public final String mMagicSpaceSwappers;
+    public final String mSuggestPuncs;
+    public final SuggestedWords mSuggestPuncList;
+    private final String mSymbolsExcludedFromWordSeparators;
+    public final CharSequence mHintToSaveText;
+
+    // From preferences:
+    public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn)
+    public final boolean mVibrateOn;
+    public final boolean mKeyPreviewPopupOn;
+    public final int mKeyPreviewPopupDismissDelay;
+    public final boolean mAutoCap;
+    public final boolean mAutoCorrectEnabled;
+    public final double mAutoCorrectionThreshold;
+    // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
+    public final boolean mBigramSuggestionEnabled;
+    // Prediction: use bigrams to predict the next word when there is no input for it yet
+    public final boolean mBigramPredictionEnabled;
+    public final boolean mUseContactsDict;
+    public final boolean mEnableSuggestionSpanInsertion;
+
+    private final boolean mShowSettingsKey;
+    private final boolean mVoiceKeyEnabled;
+    private final boolean mVoiceKeyOnMain;
+
+    public SettingsValues(final SharedPreferences prefs, final Context context,
+            final String localeStr) {
+        final Resources res = context.getResources();
+        final Locale savedLocale;
+        if (null != localeStr) {
+            final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
+            savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
+        } else {
+            savedLocale = null;
+        }
+
+        // Get the resources
+        mDelayUpdateOldSuggestions = res.getInteger(
+                R.integer.config_delay_update_old_suggestions);
+        mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
+        mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
+        String wordSeparators = mMagicSpaceStrippers + mMagicSpaceSwappers
+                + res.getString(R.string.magic_space_promoting_symbols);
+        final String symbolsExcludedFromWordSeparators =
+                res.getString(R.string.symbols_excluded_from_word_separators);
+        for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
+            wordSeparators = wordSeparators.replace(
+                    symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
+        }
+        mSymbolsExcludedFromWordSeparators = symbolsExcludedFromWordSeparators;
+        mWordSeparators = wordSeparators;
+        mSuggestPuncs = res.getString(R.string.suggested_punctuations);
+        // TODO: it would be nice not to recreate this each time we change the configuration
+        mSuggestPuncList = createSuggestPuncList(mSuggestPuncs);
+        mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
+
+        // Get the settings preferences
+        final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator();
+        mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON,
+                res.getBoolean(R.bool.config_default_vibration_enabled));
+        mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
+                res.getBoolean(R.bool.config_default_sound_enabled));
+        mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res);
+        mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res);
+        mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
+        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res);
+        mBigramSuggestionEnabled = mAutoCorrectEnabled
+                && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
+        mBigramPredictionEnabled = mBigramSuggestionEnabled
+                && isBigramPredictionEnabled(prefs, res);
+        mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res);
+        mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
+        mEnableSuggestionSpanInsertion =
+                prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
+        final boolean defaultShowSettingsKey = res.getBoolean(
+                R.bool.config_default_show_settings_key);
+        mShowSettingsKey = isShowSettingsKeyOption(res)
+                ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey)
+                : defaultShowSettingsKey;
+        final String voiceModeMain = res.getString(R.string.voice_mode_main);
+        final String voiceModeOff = res.getString(R.string.voice_mode_off);
+        final String voiceMode = prefs.getString(Settings.PREF_VOICE_SETTINGS_KEY, voiceModeMain);
+        mVoiceKeyEnabled = voiceMode != null && !voiceMode.equals(voiceModeOff);
+        mVoiceKeyOnMain = voiceMode != null && voiceMode.equals(voiceModeMain);
+
+        LocaleUtils.setSystemLocale(res, savedLocale);
+    }
+
+    public boolean isSuggestedPunctuation(int code) {
+        return mSuggestPuncs.contains(String.valueOf((char)code));
+    }
+
+    public boolean isWordSeparator(int code) {
+        return mWordSeparators.contains(String.valueOf((char)code));
+    }
+
+    public boolean isSymbolExcludedFromWordSeparators(int code) {
+        return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
+    }
+
+    public boolean isMagicSpaceStripper(int code) {
+        return mMagicSpaceStrippers.contains(String.valueOf((char)code));
+    }
+
+    public boolean isMagicSpaceSwapper(int code) {
+        return mMagicSpaceSwappers.contains(String.valueOf((char)code));
+    }
+
+    private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) {
+        final String currentAutoCorrectionSetting = sp.getString(
+                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
+                resources.getString(R.string.auto_correction_threshold_mode_index_modest));
+        final String autoCorrectionOff = resources.getString(
+                R.string.auto_correction_threshold_mode_index_off);
+        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
+    }
+
+    // Public to access from KeyboardSwitcher. Should it have access to some
+    // process-global instance instead?
+    public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) {
+        final boolean showPopupOption = resources.getBoolean(
+                R.bool.config_enable_show_popup_on_keypress_option);
+        if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview);
+        return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON,
+                resources.getBoolean(R.bool.config_default_popup_preview));
+    }
+
+    // Likewise
+    public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp,
+            Resources resources) {
+        return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
+                Integer.toString(resources.getInteger(R.integer.config_delay_after_preview))));
+    }
+
+    private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources,
+            boolean autoCorrectEnabled) {
+        final boolean showBigramSuggestionsOption = resources.getBoolean(
+                R.bool.config_enable_bigram_suggestions_option);
+        if (!showBigramSuggestionsOption) {
+            return autoCorrectEnabled;
+        }
+        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean(
+                R.bool.config_default_bigram_suggestions));
+    }
+
+    private static boolean isBigramPredictionEnabled(SharedPreferences sp,
+            Resources resources) {
+        return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean(
+                R.bool.config_default_bigram_prediction));
+    }
+
+    private static double getAutoCorrectionThreshold(SharedPreferences sp,
+            Resources resources) {
+        final String currentAutoCorrectionSetting = sp.getString(
+                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
+                resources.getString(R.string.auto_correction_threshold_mode_index_modest));
+        final String[] autoCorrectionThresholdValues = resources.getStringArray(
+                R.array.auto_correction_threshold_values);
+        // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
+        double autoCorrectionThreshold = Double.MAX_VALUE;
+        try {
+            final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
+            if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
+                autoCorrectionThreshold = Double.parseDouble(
+                        autoCorrectionThresholdValues[arrayIndex]);
+            }
+        } catch (NumberFormatException e) {
+            // Whenever the threshold settings are correct, never come here.
+            autoCorrectionThreshold = Double.MAX_VALUE;
+            Log.w(TAG, "Cannot load auto correction threshold setting."
+                    + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
+                    + ", autoCorrectionThresholdValues: "
+                    + Arrays.toString(autoCorrectionThresholdValues));
+        }
+        return autoCorrectionThreshold;
+    }
+
+    private static SuggestedWords createSuggestPuncList(final String puncs) {
+        SuggestedWords.Builder builder = new SuggestedWords.Builder();
+        if (puncs != null) {
+            for (int i = 0; i < puncs.length(); i++) {
+                builder.addWord(puncs.subSequence(i, i + 1));
+            }
+        }
+        return builder.setIsPunctuationSuggestions().build();
+    }
+
+    public static boolean isShowSettingsKeyOption(final Resources resources) {
+        return resources.getBoolean(R.bool.config_enable_show_settings_key_option);
+
+    }
+
+    public boolean isSettingsKeyEnabled() {
+        return mShowSettingsKey;
+    }
+
+    public boolean isVoiceKeyEnabled(EditorInfo editorInfo) {
+        final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
+        final int inputType = (editorInfo != null) ? editorInfo.inputType : 0;
+        return shortcutImeEnabled && mVoiceKeyEnabled
+                && !InputTypeCompatUtils.isPasswordInputType(inputType);
+    }
+
+    public boolean isVoiceKeyOnMain() {
+        return mVoiceKeyOnMain;
+    }
+}
\ No newline at end of file