Merge "Fix some warnings"
diff --git a/java/res/xml-sw600dp/key_azerty_quote.xml b/java/res/xml-sw600dp/key_azerty3_right.xml
similarity index 90%
rename from java/res/xml-sw600dp/key_azerty_quote.xml
rename to java/res/xml-sw600dp/key_azerty3_right.xml
index 0e4a8ec..a5a6e95 100644
--- a/java/res/xml-sw600dp/key_azerty_quote.xml
+++ b/java/res/xml-sw600dp/key_azerty3_right.xml
@@ -22,8 +22,8 @@
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
     <Key
-        latin:keyLabel="\'"
-        latin:keyHintLabel=":"
-        latin:moreKeys=":"
+        latin:keyLabel=":"
+        latin:keyHintLabel=";"
+        latin:moreKeys=";"
         latin:keyStyle="hasShiftedLetterHintStyle" />
 </merge>
diff --git a/java/res/xml/key_azerty_quote.xml b/java/res/xml/key_azerty3_right.xml
similarity index 100%
rename from java/res/xml/key_azerty_quote.xml
rename to java/res/xml/key_azerty3_right.xml
diff --git a/java/res/xml/rowkeys_azerty3.xml b/java/res/xml/rowkeys_azerty3.xml
index 9f4c608..2643f32 100644
--- a/java/res/xml/rowkeys_azerty3.xml
+++ b/java/res/xml/rowkeys_azerty3.xml
@@ -38,5 +38,5 @@
         latin:keyLabel="n"
         latin:moreKeys="!text/more_keys_for_n" />
     <include
-        latin:keyboardLayout="@xml/key_azerty_quote" />
+        latin:keyboardLayout="@xml/key_azerty3_right" />
 </merge>
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 6aa43b9..36f4db9 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -62,7 +62,6 @@
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.settings.DebugSettings;
-import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
 import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
@@ -203,7 +202,6 @@
 
         private final int mKeyRepeatStartTimeout;
         private final int mKeyRepeatInterval;
-        private final int mLongPressShiftLockTimeout;
         private final int mIgnoreAltCodeKeyTimeout;
         private final int mGestureRecognitionUpdateTime;
 
@@ -215,8 +213,6 @@
                     R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0);
             mKeyRepeatInterval = mainKeyboardViewAttr.getInt(
                     R.styleable.MainKeyboardView_keyRepeatInterval, 0);
-            mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt(
-                    R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0);
             mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
                     R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
             mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt(
@@ -280,31 +276,10 @@
         }
 
         @Override
-        public void startLongPressTimer(final PointerTracker tracker) {
+        public void startLongPressTimer(final PointerTracker tracker, final int delay) {
             cancelLongPressTimer();
-            if (tracker == null) {
-                return;
-            }
-            final Key key = tracker.getKey();
-            final int delay;
-            switch (key.mCode) {
-            case Constants.CODE_SHIFT:
-                delay = mLongPressShiftLockTimeout;
-                break;
-            default:
-                final int longpressTimeout =
-                        Settings.getInstance().getCurrent().mKeyLongpressTimeout;
-                if (tracker.isInSlidingKeyInputFromModifier()) {
-                    // We use longer timeout for sliding finger input started from the modifier key.
-                    delay = longpressTimeout * 3;
-                } else {
-                    delay = longpressTimeout;
-                }
-                break;
-            }
-            if (delay > 0) {
-                sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay);
-            }
+            if (delay <= 0) return;
+            sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay);
         }
 
         @Override
@@ -901,9 +876,12 @@
     }
 
     @Override
-    public void showGestureTrail(final PointerTracker tracker) {
+    public void showGestureTrail(final PointerTracker tracker,
+            final boolean showsFloatingPreviewText) {
         locatePreviewPlacerView();
-        mGestureFloatingPreviewText.setPreviewPosition(tracker);
+        if (showsFloatingPreviewText) {
+            mGestureFloatingPreviewText.setPreviewPosition(tracker);
+        }
         mGestureTrailsPreview.setPreviewPosition(tracker);
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index c7b0964..20fc109 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -34,6 +34,7 @@
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
 import com.android.inputmethod.latin.utils.ResourceUtils;
@@ -87,14 +88,14 @@
         public void dismissKeyPreview(PointerTracker tracker);
         public void showSlidingKeyInputPreview(PointerTracker tracker);
         public void dismissSlidingKeyInputPreview();
-        public void showGestureTrail(PointerTracker tracker);
+        public void showGestureTrail(PointerTracker tracker, boolean showsFloatingPreviewText);
     }
 
     public interface TimerProxy {
         public void startTypingStateTimer(Key typedKey);
         public boolean isTypingState();
         public void startKeyRepeatTimer(PointerTracker tracker);
-        public void startLongPressTimer(PointerTracker tracker);
+        public void startLongPressTimer(PointerTracker tracker, int delay);
         public void cancelLongPressTimer();
         public void startDoubleTapShiftKeyTimer();
         public void cancelDoubleTapShiftKeyTimer();
@@ -112,7 +113,7 @@
             @Override
             public void startKeyRepeatTimer(PointerTracker tracker) {}
             @Override
-            public void startLongPressTimer(PointerTracker tracker) {}
+            public void startLongPressTimer(PointerTracker tracker, int delay) {}
             @Override
             public void cancelLongPressTimer() {}
             @Override
@@ -137,6 +138,7 @@
         public final int mTouchNoiseThresholdTime;
         public final int mTouchNoiseThresholdDistance;
         public final int mSuppressKeyPreviewAfterBatchInputDuration;
+        public final int mLongPressShiftLockTimeout;
 
         public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
 
@@ -145,6 +147,7 @@
             mTouchNoiseThresholdTime = 0;
             mTouchNoiseThresholdDistance = 0;
             mSuppressKeyPreviewAfterBatchInputDuration = 0;
+            mLongPressShiftLockTimeout = 0;
         }
 
         public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
@@ -156,6 +159,8 @@
                     R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0);
             mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt(
                     R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0);
+            mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt(
+                    R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0);
         }
     }
 
@@ -327,6 +332,7 @@
     // the more keys panel currently being shown. equals null if no panel is active.
     private MoreKeysPanel mMoreKeysPanel;
 
+    private static final int MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT = 3;
     // true if this pointer is in a sliding key input.
     boolean mIsInSlidingKeyInput;
     // true if this pointer is in a sliding key input from a modifier key,
@@ -602,10 +608,6 @@
         return mIsInSlidingKeyInput;
     }
 
-    public boolean isInSlidingKeyInputFromModifier() {
-        return mIsInSlidingKeyInputFromModifier;
-    }
-
     public Key getKey() {
         return mCurrentKey;
     }
@@ -753,7 +755,7 @@
         return sPointerTrackerQueue.size();
     }
 
-    public boolean isOldestTrackerInQueue() {
+    private boolean isOldestTrackerInQueue() {
         return sPointerTrackerQueue.getOldestElement() == this;
     }
 
@@ -776,7 +778,9 @@
             dismissAllMoreKeysPanels();
         }
         mTimerProxy.cancelLongPressTimer();
-        mDrawingProxy.showGestureTrail(this);
+        // A gesture floating preview text will be shown at the oldest pointer/finger on the screen.
+        mDrawingProxy.showGestureTrail(
+                this, isOldestTrackerInQueue() /* showsFloatingPreviewText */);
     }
 
     public void updateBatchInputByTimer(final long eventTime) {
@@ -792,7 +796,9 @@
         if (mIsTrackingForActionDisabled) {
             return;
         }
-        mDrawingProxy.showGestureTrail(this);
+        // A gesture floating preview text will be shown at the oldest pointer/finger on the screen.
+        mDrawingProxy.showGestureTrail(
+                this, isOldestTrackerInQueue() /* showsFloatingPreviewText */);
     }
 
     private void updateBatchInput(final long eventTime) {
@@ -833,7 +839,9 @@
         if (mIsTrackingForActionDisabled) {
             return;
         }
-        mDrawingProxy.showGestureTrail(this);
+        // A gesture floating preview text will be shown at the oldest pointer/finger on the screen.
+        mDrawingProxy.showGestureTrail(
+                this, isOldestTrackerInQueue() /* showsFloatingPreviewText */);
     }
 
     private void cancelBatchInput() {
@@ -1013,7 +1021,9 @@
             final int translatedY = mMoreKeysPanel.translateY(y);
             mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime);
             onMoveKey(x, y);
-            mDrawingProxy.showSlidingKeyInputPreview(this);
+            if (mIsInSlidingKeyInputFromModifier) {
+                mDrawingProxy.showSlidingKeyInputPreview(this);
+            }
             return;
         }
         onMoveEventInternal(x, y, eventTime);
@@ -1168,7 +1178,9 @@
                 slideOutFromOldKey(oldKey, x, y);
             }
         }
-        mDrawingProxy.showSlidingKeyInputPreview(this);
+        if (mIsInSlidingKeyInputFromModifier) {
+            mDrawingProxy.showSlidingKeyInputPreview(this);
+        }
     }
 
     public void onUpEvent(final int x, final int y, final long eventTime) {
@@ -1353,7 +1365,22 @@
         // We always need to start the long press timer if the key has its more keys regardless of
         // whether or not we are in the sliding input mode.
         if (mIsInSlidingKeyInput && key.mMoreKeys == null) return;
-        mTimerProxy.startLongPressTimer(this);
+        final int delay;
+        switch (key.mCode) {
+        case Constants.CODE_SHIFT:
+            delay = sParams.mLongPressShiftLockTimeout;
+            break;
+        default:
+            final int longpressTimeout = Settings.getInstance().getCurrent().mKeyLongpressTimeout;
+            if (mIsInSlidingKeyInputFromModifier) {
+                // We use longer timeout for sliding finger input started from the modifier key.
+                delay = longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT;
+            } else {
+                delay = longpressTimeout;
+            }
+            break;
+        }
+        mTimerProxy.startLongPressTimer(this, delay);
     }
 
     private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
index 9bfddba..c6dd9e1 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
@@ -115,9 +115,7 @@
 
     @Override
     public void setPreviewPosition(final PointerTracker tracker) {
-        final boolean needsToUpdateLastPointer =
-                tracker.isOldestTrackerInQueue() && isPreviewEnabled();
-        if (!needsToUpdateLastPointer) {
+        if (!isPreviewEnabled()) {
             return;
         }
         tracker.getLastCoordinates(mLastPointerCoords);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
index 5c9d367..2787ebf 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
@@ -32,7 +32,7 @@
 public final class SlidingKeyInputPreview extends AbstractDrawingPreview {
     private final float mPreviewBodyRadius;
 
-    private boolean mShowSlidingKeyInputPreview;
+    private boolean mShowsSlidingKeyInputPreview;
     private final int[] mPreviewFrom = CoordinateUtils.newInstance();
     private final int[] mPreviewTo = CoordinateUtils.newInstance();
 
@@ -62,7 +62,7 @@
     }
 
     public void dismissSlidingKeyInputPreview() {
-        mShowSlidingKeyInputPreview = false;
+        mShowsSlidingKeyInputPreview = false;
         getDrawingView().invalidate();
     }
 
@@ -72,7 +72,7 @@
      */
     @Override
     public void drawPreview(final Canvas canvas) {
-        if (!isPreviewEnabled() || !mShowSlidingKeyInputPreview) {
+        if (!isPreviewEnabled() || !mShowsSlidingKeyInputPreview) {
             return;
         }
 
@@ -90,13 +90,9 @@
      */
     @Override
     public void setPreviewPosition(final PointerTracker tracker) {
-        if (!tracker.isInSlidingKeyInputFromModifier()) {
-            mShowSlidingKeyInputPreview = false;
-            return;
-        }
         tracker.getDownCoordinates(mPreviewFrom);
         tracker.getLastCoordinates(mPreviewTo);
-        mShowSlidingKeyInputPreview = true;
+        mShowsSlidingKeyInputPreview = true;
         getDrawingView().invalidate();
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 9366abd..1211ea5 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -548,8 +548,9 @@
         }
         mSuggest = new Suggest(this /* Context */, subtypeLocale,
                 this /* SuggestInitializationListener */);
-        if (mSettings.getCurrent().mCorrectionEnabled) {
-            mSuggest.setAutoCorrectionThreshold(mSettings.getCurrent().mAutoCorrectionThreshold);
+        final SettingsValues settingsValues = mSettings.getCurrent();
+        if (settingsValues.mCorrectionEnabled) {
+            mSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold);
         }
 
         mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
@@ -714,7 +715,9 @@
         super.onStartInputView(editorInfo, restarting);
         final KeyboardSwitcher switcher = mKeyboardSwitcher;
         final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView();
-        final SettingsValues currentSettingsValues = mSettings.getCurrent();
+        // If we are starting input in a different text field from before, we'll have to reload
+        // settings, so currentSettingsValues can't be final.
+        SettingsValues currentSettingsValues = mSettings.getCurrent();
 
         if (editorInfo == null) {
             Log.e(TAG, "Null EditorInfo in onStartInputView()");
@@ -808,7 +811,8 @@
         if (isDifferentTextField) {
             mainKeyboardView.closing();
             loadSettings();
-            // TODO: Need to update currentSettingsValues after loadSettings()
+            currentSettingsValues = mSettings.getCurrent();
+
             if (mSuggest != null && currentSettingsValues.mCorrectionEnabled) {
                 mSuggest.setAutoCorrectionThreshold(currentSettingsValues.mAutoCorrectionThreshold);
             }
@@ -1213,10 +1217,11 @@
     private void resetEntireInputState(final int newCursorPosition) {
         final boolean shouldFinishComposition = mWordComposer.isComposingWord();
         resetComposingState(true /* alsoResetLastComposedWord */);
-        if (mSettings.getCurrent().mBigramPredictionEnabled) {
+        final SettingsValues settingsValues = mSettings.getCurrent();
+        if (settingsValues.mBigramPredictionEnabled) {
             clearSuggestionStrip();
         } else {
-            setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
+            setSuggestedWords(settingsValues.mSuggestPuncList, false);
         }
         mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition);
     }
@@ -1290,8 +1295,9 @@
     }
 
     private boolean maybeDoubleSpacePeriod() {
-        if (!mSettings.getCurrent().mCorrectionEnabled) return false;
-        if (!mSettings.getCurrent().mUseDoubleSpacePeriod) return false;
+        final SettingsValues settingsValues = mSettings.getCurrent();
+        if (!settingsValues.mCorrectionEnabled) return false;
+        if (!settingsValues.mUseDoubleSpacePeriod) return false;
         if (!mHandler.isAcceptingDoubleSpacePeriod()) return false;
         final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
         if (lastThree != null && lastThree.length() == 3
@@ -1551,12 +1557,13 @@
             final int spaceState) {
         mSpaceState = SPACE_STATE_NONE;
         final boolean didAutoCorrect;
-        if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
+        final SettingsValues settingsValues = mSettings.getCurrent();
+        if (settingsValues.isWordSeparator(primaryCode)) {
             didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
         } else {
             didAutoCorrect = false;
             if (SPACE_STATE_PHANTOM == spaceState) {
-                if (mSettings.isInternal()) {
+                if (settingsValues.mIsInternal) {
                     if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
                         LatinImeLoggerUtils.onAutoCorrection(
                                 "", mWordComposer.getTypedWord(), " ", mWordComposer);
@@ -1616,8 +1623,9 @@
         BatchInputUpdater.getInstance().onStartBatchInput(this);
         mHandler.cancelUpdateSuggestionStrip();
         mConnection.beginBatchEdit();
+        final SettingsValues settingsValues = mSettings.getCurrent();
         if (mWordComposer.isComposingWord()) {
-            if (mSettings.isInternal()) {
+            if (settingsValues.mIsInternal) {
                 if (mWordComposer.isBatchMode()) {
                     LatinImeLoggerUtils.onAutoCorrection(
                             "", mWordComposer.getTypedWord(), " ", mWordComposer);
@@ -1646,7 +1654,7 @@
         }
         final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
         if (Character.isLetterOrDigit(codePointBeforeCursor)
-                || mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) {
+                || settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) {
             mSpaceState = SPACE_STATE_PHANTOM;
         }
         mConnection.endBatchEdit();
@@ -1866,8 +1874,9 @@
                 mConnection.deleteSurroundingText(1, 0);
             }
         } else {
+            final SettingsValues currentSettings = mSettings.getCurrent();
             if (mLastComposedWord.canRevertCommit()) {
-                if (mSettings.isInternal()) {
+                if (currentSettings.mIsInternal) {
                     LatinImeLoggerUtils.onAutoCorrectionCancellation();
                 }
                 revertCommit();
@@ -1944,7 +1953,7 @@
                     }
                 }
             }
-            if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
+            if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
                 restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
             }
         }
@@ -1961,8 +1970,9 @@
         }
         if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
                 && isFromSuggestionStrip) {
-            if (mSettings.getCurrent().isUsuallyPrecededBySpace(code)) return false;
-            if (mSettings.getCurrent().isUsuallyFollowedBySpace(code)) return true;
+            final SettingsValues currentSettings = mSettings.getCurrent();
+            if (currentSettings.isUsuallyPrecededBySpace(code)) return false;
+            if (currentSettings.isUsuallyFollowedBySpace(code)) return true;
             mConnection.removeTrailingSpace();
         }
         return false;
@@ -1974,8 +1984,8 @@
 
         // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
         // See onStartBatchInput() to see how to do it.
-        if (SPACE_STATE_PHANTOM == spaceState &&
-                !mSettings.getCurrent().isWordConnector(primaryCode)) {
+        final SettingsValues currentSettings = mSettings.getCurrent();
+        if (SPACE_STATE_PHANTOM == spaceState && !currentSettings.isWordConnector(primaryCode)) {
             if (isComposingWord) {
                 // Sanity check
                 throw new RuntimeException("Should not be composing here");
@@ -1993,9 +2003,9 @@
         // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
         // thread here.
         if (!isComposingWord && (isAlphabet(primaryCode)
-                || mSettings.getCurrent().isWordConnector(primaryCode))
-                && mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
-                !mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
+                || currentSettings.isWordConnector(primaryCode))
+                && currentSettings.isSuggestionsRequested(mDisplayOrientation) &&
+                !mConnection.isCursorTouchingWord(currentSettings)) {
             // Reset entirely the composing state anyway, then start composing a new word unless
             // the character is a single quote. The idea here is, single quote is not a
             // separator and it should be treated as a normal character, except in the first
@@ -2038,7 +2048,7 @@
             if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint();
         }
         mHandler.postUpdateSuggestionStrip();
-        if (mSettings.isInternal()) {
+        if (currentSettings.mIsInternal) {
             LatinImeLoggerUtils.onNonSeparator((char)primaryCode, x, y);
         }
     }
@@ -2051,9 +2061,10 @@
             final CharSequence selectedText =
                     mConnection.getSelectedText(0 /* flags, 0 for no styles */);
             if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection
+            final SettingsValues currentSettings = mSettings.getCurrent();
             mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd,
-                    selectedText.toString(), mSettings.getCurrentLocale(),
-                    mSettings.getWordSeparators());
+                    selectedText.toString(), currentSettings.mLocale,
+                    currentSettings.mWordSeparators);
             // We trim leading and trailing whitespace.
             mRecapitalizeStatus.trim();
             // Trimming the object may have changed the length of the string, and we need to
@@ -2087,8 +2098,9 @@
             // first so that we can insert the separator at the current cursor position.
             resetEntireInputState(mLastSelectionStart);
         }
+        final SettingsValues currentSettings = mSettings.getCurrent();
         if (mWordComposer.isComposingWord()) {
-            if (mSettings.getCurrent().mCorrectionEnabled) {
+            if (currentSettings.mCorrectionEnabled) {
                 // TODO: maybe cache Strings in an <String> sparse array or something
                 commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
                 didAutoCorrect = true;
@@ -2101,7 +2113,7 @@
                 Constants.SUGGESTION_STRIP_COORDINATE == x);
 
         if (SPACE_STATE_PHANTOM == spaceState &&
-                mSettings.getCurrent().isUsuallyPrecededBySpace(primaryCode)) {
+                currentSettings.isUsuallyPrecededBySpace(primaryCode)) {
             promotePhantomSpace();
         }
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -2110,7 +2122,7 @@
         sendKeyCodePoint(primaryCode);
 
         if (Constants.CODE_SPACE == primaryCode) {
-            if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
+            if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
                 if (maybeDoubleSpacePeriod()) {
                     mSpaceState = SPACE_STATE_DOUBLE;
                 } else if (!isShowingPunctuationList()) {
@@ -2125,7 +2137,7 @@
                 swapSwapperAndSpace();
                 mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
             } else if (SPACE_STATE_PHANTOM == spaceState
-                    && mSettings.getCurrent().isUsuallyFollowedBySpace(primaryCode)) {
+                    && currentSettings.isUsuallyFollowedBySpace(primaryCode)) {
                 // If we are in phantom space state, and the user presses a separator, we want to
                 // stay in phantom space state so that the next keypress has a chance to add the
                 // space. For example, if I type "Good dat", pick "day" from the suggestion strip
@@ -2143,7 +2155,7 @@
             // already displayed or not, so it's okay.
             setPunctuationSuggestions();
         }
-        if (mSettings.isInternal()) {
+        if (currentSettings.mIsInternal) {
             LatinImeLoggerUtils.onSeparator((char)primaryCode, x, y);
         }
 
@@ -2176,17 +2188,18 @@
     }
 
     private boolean isSuggestionsStripVisible() {
+        final SettingsValues currentSettings = mSettings.getCurrent();
         if (mSuggestionStripView == null)
             return false;
         if (mSuggestionStripView.isShowingAddToDictionaryHint())
             return true;
-        if (null == mSettings.getCurrent())
+        if (null == currentSettings)
             return false;
-        if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation))
+        if (!currentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation))
             return false;
-        if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn())
+        if (currentSettings.isApplicationSpecifiedCompletionsOn())
             return true;
-        return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation);
+        return currentSettings.isSuggestionsRequested(mDisplayOrientation);
     }
 
     private void clearSuggestionStrip() {
@@ -2219,10 +2232,11 @@
 
     private void updateSuggestionStrip() {
         mHandler.cancelUpdateSuggestionStrip();
+        final SettingsValues currentSettings = mSettings.getCurrent();
 
         // Check if we have a suggestion engine attached.
         if (mSuggest == null
-                || !mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
+                || !currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
             if (mWordComposer.isComposingWord()) {
                 Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not "
                         + "requested!");
@@ -2230,7 +2244,7 @@
             return;
         }
 
-        if (!mWordComposer.isComposingWord() && !mSettings.getCurrent().mBigramPredictionEnabled) {
+        if (!mWordComposer.isComposingWord() && !currentSettings.mBigramPredictionEnabled) {
             setPunctuationSuggestions();
             return;
         }
@@ -2251,12 +2265,13 @@
         // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we
         // should just skip whitespace if any, so 1.
         // TODO: this is slow (2-way IPC) - we should probably cache this instead.
+        final SettingsValues currentSettings = mSettings.getCurrent();
         final String prevWord =
-                mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators,
+                mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
                 mWordComposer.isComposingWord() ? 2 : 1);
         return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
-                mSettings.getBlockPotentiallyOffensive(),
-                mSettings.getCurrent().mCorrectionEnabled, sessionId);
+                currentSettings.mBlockPotentiallyOffensive,
+                currentSettings.mCorrectionEnabled, sessionId);
     }
 
     private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) {
@@ -2382,18 +2397,19 @@
         }
 
         mConnection.beginBatchEdit();
+        final SettingsValues currentSettings = mSettings.getCurrent();
         if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0
                 // In the batch input mode, a manually picked suggested word should just replace
                 // the current batch input text and there is no need for a phantom space.
                 && !mWordComposer.isBatchMode()) {
             final int firstChar = Character.codePointAt(suggestion, 0);
-            if (!mSettings.getCurrent().isWordSeparator(firstChar)
-                    || mSettings.getCurrent().isUsuallyPrecededBySpace(firstChar)) {
+            if (!currentSettings.isWordSeparator(firstChar)
+                    || currentSettings.isUsuallyPrecededBySpace(firstChar)) {
                 promotePhantomSpace();
             }
         }
 
-        if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()
+        if (currentSettings.isApplicationSpecifiedCompletionsOn()
                 && mApplicationSpecifiedCompletions != null
                 && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
             mSuggestedWords = SuggestedWords.EMPTY;
@@ -2438,13 +2454,13 @@
                         // If the suggestion is not in the dictionary, the hint should be shown.
                         && !AutoCorrectionUtils.isValidWord(mSuggest, suggestion, true);
 
-        if (mSettings.isInternal()) {
+        if (currentSettings.mIsInternal) {
             LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE,
                     Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
         }
         if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) {
             mSuggestionStripView.showAddToDictionaryHint(
-                    suggestion, mSettings.getCurrent().mHintToSaveText);
+                    suggestion, currentSettings.mHintToSaveText);
         } else {
             // If we're not showing the "Touch again to save", then update the suggestion strip.
             mHandler.postUpdateSuggestionStrip();
@@ -2470,10 +2486,11 @@
     }
 
     private void setPunctuationSuggestions() {
-        if (mSettings.getCurrent().mBigramPredictionEnabled) {
+        final SettingsValues currentSettings = mSettings.getCurrent();
+        if (currentSettings.mBigramPredictionEnabled) {
             clearSuggestionStrip();
         } else {
-            setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
+            setSuggestedWords(currentSettings.mSuggestPuncList, false);
         }
         setAutoCorrectionIndicator(false);
         setSuggestionStripShown(isSuggestionsStripVisible());
@@ -2486,7 +2503,8 @@
         // If correction is not enabled, we don't add words to the user history dictionary.
         // That's to avoid unintended additions in some sensitive fields, or fields that
         // expect to receive non-words.
-        if (!mSettings.getCurrent().mCorrectionEnabled) return null;
+        final SettingsValues currentSettings = mSettings.getCurrent();
+        if (!currentSettings.mCorrectionEnabled) return null;
 
         final Suggest suggest = mSuggest;
         final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary;
@@ -2494,8 +2512,7 @@
             // Avoid concurrent issue
             return null;
         }
-        final String prevWord
-                = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2);
+        final String prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators, 2);
         final String secondWord;
         if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
             secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale());
@@ -2524,8 +2541,9 @@
         if (mLastSelectionStart != mLastSelectionEnd) return;
         // If we don't know the cursor location, return.
         if (mLastSelectionStart < 0) return;
-        if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
-        final TextRange range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
+        final SettingsValues currentSettings = mSettings.getCurrent();
+        if (!mConnection.isCursorTouchingWord(currentSettings)) return;
+        final TextRange range = mConnection.getWordRangeAtCursor(currentSettings.mWordSeparators,
                 0 /* additionalPrecedingWordsCount */);
         if (null == range) return; // Happens if we don't have an input connection at all
         // If for some strange reason (editor bug or so) we measure the text before the cursor as
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index b690fed..2631cd3 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -93,7 +93,6 @@
 
     private Resources mRes;
     private SharedPreferences mPrefs;
-    private Locale mCurrentLocale;
     private SettingsValues mSettingsValues;
 
     private static final Settings sInstance = new Settings();
@@ -128,16 +127,15 @@
             Log.w(TAG, "onSharedPreferenceChanged called before loadSettings.");
             return;
         }
-        loadSettings(mCurrentLocale, mSettingsValues.mInputAttributes);
+        loadSettings(mSettingsValues.mLocale, mSettingsValues.mInputAttributes);
     }
 
     public void loadSettings(final Locale locale, final InputAttributes inputAttributes) {
-        mCurrentLocale = locale;
         final SharedPreferences prefs = mPrefs;
         final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
             @Override
             protected SettingsValues job(final Resources res) {
-                return new SettingsValues(prefs, res, inputAttributes);
+                return new SettingsValues(prefs, locale, res, inputAttributes);
             }
         };
         mSettingsValues = job.runInLocale(mRes, locale);
@@ -160,10 +158,6 @@
         return mSettingsValues.isWordSeparator(code);
     }
 
-    public Locale getCurrentLocale() {
-        return mCurrentLocale;
-    }
-
     public boolean getBlockPotentiallyOffensive() {
         return mSettingsValues.mBlockPotentiallyOffensive;
     }
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index a7462bc..8aafb07 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -36,6 +36,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Locale;
 
 /**
  * When you call the constructor of this class, you may want to change the current system locale by
@@ -74,6 +75,7 @@
     public final boolean mGestureFloatingPreviewTextEnabled;
     public final boolean mSlidingKeyInputPreviewEnabled;
     public final int mKeyLongpressTimeout;
+    public final Locale mLocale;
 
     // From the input box
     public final InputAttributes mInputAttributes;
@@ -96,8 +98,9 @@
     // Debug settings
     public final boolean mIsInternal;
 
-    public SettingsValues(final SharedPreferences prefs, final Resources res,
+    public SettingsValues(final SharedPreferences prefs, final Locale locale, final Resources res,
             final InputAttributes inputAttributes) {
+        mLocale = locale;
         // Get the resources
         mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
         mSymbolsPrecededBySpace =