diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 9e4c1ea797da875c86d7172ca134df0a08cd90c6..8d40e7aa5a31e8c354250de0c1bb5053cbdcaa4b 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -138,8 +138,7 @@ public class Keyboard {
 
         mProximityInfo = new ProximityInfo(
                 params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
-                mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrectionXs,
-                params.mTouchPositionCorrectionYs, params.mTouchPositionCorrectionRadii);
+                mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
     }
 
     public ProximityInfo getProximityInfo() {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 837a53391713f666f78f1ff755dc4f56452a7c22..e9a7fd07772172ff5cfb749243d44699a98bf640 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -264,7 +264,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         if (keyboard == null) {
             final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale);
             try {
-                keyboard = new LatinKeyboard.Builder(mThemeContext).load(id).build();
+                final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(mThemeContext);
+                builder.load(id);
+                builder.setTouchPositionCorrectionEnabled(
+                        mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
+                                LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
+                keyboard = builder.build();
             } finally {
                 LocaleUtils.setSystemLocale(mResources, savedLocale);
             }
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index cc6feeb4aed4782900bdf6506517de8d6ff74802..34a77e1ca43d8d2e813e37b19d744ba63bdeb30f 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard;
 import android.graphics.Rect;
 
 import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.internal.KeyboardParams.TouchPositionCorrection;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.Utils;
 import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
@@ -32,8 +33,6 @@ public class ProximityInfo {
     /** Number of key widths from current touch point to search for nearest keys. */
     private static float SEARCH_DISTANCE = 1.2f;
     private static final int[] EMPTY_INT_ARRAY = new int[0];
-    private static final String SUPPORT_TOUCH_POSITION_CORRECTION =
-            "SupportTouchPositionCorrection";
 
     private final int mKeyHeight;
     private final int mGridWidth;
@@ -46,13 +45,8 @@ public class ProximityInfo {
     private final int mKeyboardHeight;
     private final int[][] mGridNeighbors;
 
-    private final float[] mTouchPositionCorrectionXs;
-    private final float[] mTouchPositionCorrectionYs;
-    private final float[] mTouchPositionCorrectionRadii;
-
     ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
-            int keyHeight, List<Key> keys, float[] touchPositionCorrectionXs,
-            float[] touchPositionCorrectionYs, float[] touchPositionCorrectionRadii) {
+            int keyHeight, List<Key> keys, TouchPositionCorrection touchPositionCorrection) {
         mGridWidth = gridWidth;
         mGridHeight = gridHeight;
         mGridSize = mGridWidth * mGridHeight;
@@ -61,19 +55,16 @@ public class ProximityInfo {
         mKeyboardMinWidth = minWidth;
         mKeyboardHeight = height;
         mKeyHeight = keyHeight;
-        mTouchPositionCorrectionXs = touchPositionCorrectionXs;
-        mTouchPositionCorrectionYs = touchPositionCorrectionYs;
-        mTouchPositionCorrectionRadii = touchPositionCorrectionRadii;
         mGridNeighbors = new int[mGridSize][];
         if (minWidth == 0 || height == 0) {
             // No proximity required. Keyboard might be mini keyboard.
             return;
         }
-        computeNearestNeighbors(keyWidth, keys);
+        computeNearestNeighbors(keyWidth, keys, touchPositionCorrection);
     }
 
     public static ProximityInfo createDummyProximityInfo() {
-        return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null, null, null);
+        return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null);
     }
 
     public static ProximityInfo createSpellCheckerProximityInfo() {
@@ -98,7 +89,8 @@ public class ProximityInfo {
     private native void releaseProximityInfoNative(int nativeProximityInfo);
 
     private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth,
-            int keyboardHeight, List<Key> keys) {
+            int keyboardHeight, List<Key> keys,
+            TouchPositionCorrection touchPositionCorrection) {
         int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
         Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE);
         for (int i = 0; i < mGridSize; ++i) {
@@ -123,23 +115,16 @@ public class ProximityInfo {
             keyCharCodes[i] = key.mCode;
         }
 
-        final SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
-        final boolean hasTouchPositionCorrectionData =
-                switcher.currentSubtypeContainsExtraValueKey(SUPPORT_TOUCH_POSITION_CORRECTION)
-                && mTouchPositionCorrectionXs != null
-                && mTouchPositionCorrectionYs != null
-                && mTouchPositionCorrectionRadii != null
-                && mTouchPositionCorrectionXs.length > 0
-                && mTouchPositionCorrectionYs.length > 0
-                && mTouchPositionCorrectionRadii.length > 0;
-        final float[] sweetSpotCenterXs =
-                hasTouchPositionCorrectionData ? new float[keyCount] : null;
-        final float[] sweetSpotCenterYs =
-                hasTouchPositionCorrectionData ? new float[keyCount] : null;
-        final float[] sweetSpotRadii =
-                hasTouchPositionCorrectionData ? new float[keyCount] : null;
-        if (hasTouchPositionCorrectionData) {
-            calculateSweetSpot(keys, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+        float[] sweetSpotCenterXs = null;
+        float[] sweetSpotCenterYs = null;
+        float[] sweetSpotRadii = null;
+
+        if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
+            sweetSpotCenterXs = new float[keyCount];
+            sweetSpotCenterYs = new float[keyCount];
+            sweetSpotRadii = new float[keyCount];
+            calculateSweetSpot(keys, touchPositionCorrection,
+                    sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
         }
 
         mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE,
@@ -148,21 +133,24 @@ public class ProximityInfo {
                 sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
     }
 
-    private void calculateSweetSpot(List<Key> keys, float[] sweetSpotCenterXs,
-            float[] sweetSpotCenterYs, float[] sweetSpotRadii) {
+    private void calculateSweetSpot(List<Key> keys, TouchPositionCorrection touchPositionCorrection,
+            float[] sweetSpotCenterXs, float[] sweetSpotCenterYs, float[] sweetSpotRadii) {
         final int keyCount = keys.size();
+        final float[] xs = touchPositionCorrection.mXs;
+        final float[] ys = touchPositionCorrection.mYs;
+        final float[] radii = touchPositionCorrection.mRadii;
         for (int i = 0; i < keyCount; ++i) {
             final Key key = keys.get(i);
             final Rect hitBox = key.mHitBox;
             final int row = hitBox.top / mKeyHeight;
-            if (row < mTouchPositionCorrectionRadii.length) {
+            if (row < radii.length) {
                 final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
                 final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
                 final float hitBoxWidth = hitBox.right - hitBox.left;
                 final float hitBoxHeight = hitBox.bottom - hitBox.top;
-                final float x = mTouchPositionCorrectionXs[row];
-                final float y = mTouchPositionCorrectionYs[row];
-                final float radius = mTouchPositionCorrectionRadii[row];
+                final float x = xs[row];
+                final float y = ys[row];
+                final float radius = radii[row];
                 sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
                 sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
                 sweetSpotRadii[i] = radius
@@ -187,7 +175,8 @@ public class ProximityInfo {
         }
     }
 
-    private void computeNearestNeighbors(int defaultWidth, List<Key> keys) {
+    private void computeNearestNeighbors(int defaultWidth, List<Key> keys,
+            TouchPositionCorrection touchPositionCorrection) {
         final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE);
         final int threshold = thresholdBase * thresholdBase;
         // Round-up so we don't have any pixels outside the grid
@@ -210,7 +199,8 @@ public class ProximityInfo {
                 mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = cell;
             }
         }
-        setProximityInfo(mGridNeighbors, mKeyboardMinWidth, mKeyboardHeight, keys);
+        setProximityInfo(mGridNeighbors, mKeyboardMinWidth, mKeyboardHeight, keys,
+                touchPositionCorrection);
     }
 
     public int[] getNearestKeys(int x, int y) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index e723dc19a2e1184efe566b5d8ce636bb3ea2b79e..d16c71c7e9d6d74a1ca3edc0c27a309f74571365 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -127,8 +127,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
     private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
     private static final int DEFAULT_KEYBOARD_ROWS = 4;
 
-    private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
-
     protected final KP mParams;
     protected final Context mContext;
     protected final Resources mResources;
@@ -254,10 +252,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
     }
 
     private static void setTouchPositionCorrectionData(Context context, KeyboardParams params) {
-        params.mTouchPositionCorrectionXs = null;
-        params.mTouchPositionCorrectionYs = null;
-        params.mTouchPositionCorrectionRadii = null;
-
         final TypedArray a = context.obtainStyledAttributes(
                 null, R.styleable.Keyboard, R.attr.keyboardStyle, 0);
         params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0);
@@ -270,39 +264,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
         }
 
         final String[] data = context.getResources().getStringArray(resourceId);
-        final int dataLength = data.length;
-        if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
-            if (LatinImeLogger.sDBG)
-                throw new RuntimeException("the size of touch position correction data is invalid");
-            return;
-        }
-
-        final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
-        params.mTouchPositionCorrectionXs = new float[length];
-        params.mTouchPositionCorrectionYs = new float[length];
-        params.mTouchPositionCorrectionRadii = new float[length];
-        try {
-            for (int i = 0; i < dataLength; ++i) {
-                final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
-                final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
-                final float value = Float.parseFloat(data[i]);
-                if (type == 0) {
-                    params.mTouchPositionCorrectionXs[index] = value;
-                } else if (type == 1) {
-                    params.mTouchPositionCorrectionYs[index] = value;
-                } else {
-                    params.mTouchPositionCorrectionRadii[index] = value;
-                }
-            }
-        } catch (NumberFormatException e) {
-            if (LatinImeLogger.sDBG) {
-                throw new RuntimeException(
-                        "the number format for touch position correction data is invalid");
-            }
-            params.mTouchPositionCorrectionXs = null;
-            params.mTouchPositionCorrectionYs = null;
-            params.mTouchPositionCorrectionRadii = null;
-        }
+        params.mTouchPositionCorrection.load(data);
     }
 
     public KeyboardBuilder<KP> load(KeyboardId id) {
@@ -319,6 +281,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
         return this;
     }
 
+    public void setTouchPositionCorrectionEnabled(boolean enabled) {
+        mParams.mTouchPositionCorrection.setEnabled(enabled);
+    }
+
     public Keyboard build() {
         return new Keyboard(mParams);
     }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
index d1aea72a5cd77fbfa31054f91e237700d0c50130..64cd37c4b977bc164f269425de491145ee0444a3 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable;
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.latin.LatinImeLogger;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -68,9 +69,62 @@ public class KeyboardParams {
     public int mMostCommonKeyHeight = 0;
     public int mMostCommonKeyWidth = 0;
 
-    public float[] mTouchPositionCorrectionXs;
-    public float[] mTouchPositionCorrectionYs;
-    public float[] mTouchPositionCorrectionRadii;
+    public final TouchPositionCorrection mTouchPositionCorrection = new TouchPositionCorrection();
+
+    public static class TouchPositionCorrection {
+        private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
+
+        public boolean mEnabled;
+        public float[] mXs;
+        public float[] mYs;
+        public float[] mRadii;
+
+        public void load(String[] data) {
+            final int dataLength = data.length;
+            if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
+                if (LatinImeLogger.sDBG)
+                    throw new RuntimeException(
+                            "the size of touch position correction data is invalid");
+                return;
+            }
+
+            final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+            mXs = new float[length];
+            mYs = new float[length];
+            mRadii = new float[length];
+            try {
+                for (int i = 0; i < dataLength; ++i) {
+                    final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+                    final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+                    final float value = Float.parseFloat(data[i]);
+                    if (type == 0) {
+                        mXs[index] = value;
+                    } else if (type == 1) {
+                        mYs[index] = value;
+                    } else {
+                        mRadii[index] = value;
+                    }
+                }
+            } catch (NumberFormatException e) {
+                if (LatinImeLogger.sDBG) {
+                    throw new RuntimeException(
+                            "the number format for touch position correction data is invalid");
+                }
+                mXs = null;
+                mYs = null;
+                mRadii = null;
+            }
+        }
+
+        public void setEnabled(boolean enabled) {
+            mEnabled = enabled;
+        }
+
+        public boolean isValid() {
+            return mEnabled && mXs != null && mYs != null && mRadii != null
+                && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
+        }
+    }
 
     protected void clearKeys() {
         mKeys.clear();
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 036873cd9c78e439bfc2415097f336f6cac6692b..36e97af11d0693c3757674d258106eacbd9fa03f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -117,6 +117,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
      */
     public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
 
+    /**
+     * The subtype extra value used to indicate that the subtype keyboard layout supports touch
+     * position correction.
+     */
+    public static final String SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION =
+            "SupportTouchPositionCorrection";
     /**
      * The subtype extra value used to indicate that the subtype keyboard layout should be loaded
      * from the specified locale.