diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 9e4c1ea79..8d40e7aa5 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 837a53391..e9a7fd077 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 cc6feeb4a..34a77e1ca 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 keys, float[] touchPositionCorrectionXs, - float[] touchPositionCorrectionYs, float[] touchPositionCorrectionRadii) { + int keyHeight, List 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.emptyList(), null, null, null); + return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.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 keys) { + int keyboardHeight, List 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 keys, float[] sweetSpotCenterXs, - float[] sweetSpotCenterYs, float[] sweetSpotRadii) { + private void calculateSweetSpot(List 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 keys) { + private void computeNearestNeighbors(int defaultWidth, List 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 e723dc19a..d16c71c7e 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 { 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 { } 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 { } 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 load(KeyboardId id) { @@ -319,6 +281,10 @@ public class KeyboardBuilder { 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 d1aea72a5..64cd37c4b 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 036873cd9..36e97af11 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.