Merge "Pass the touch position correction flag from KeyboardSwitcher."

This commit is contained in:
Yusuke Nojima 2011-10-03 04:42:53 -07:00 committed by Android (Google) Code Review
commit a25dd3b5c3
6 changed files with 104 additions and 84 deletions

View file

@ -138,8 +138,7 @@ public class Keyboard {
mProximityInfo = new ProximityInfo( mProximityInfo = new ProximityInfo(
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrectionXs, mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
params.mTouchPositionCorrectionYs, params.mTouchPositionCorrectionRadii);
} }
public ProximityInfo getProximityInfo() { public ProximityInfo getProximityInfo() {

View file

@ -264,7 +264,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
if (keyboard == null) { if (keyboard == null) {
final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale); final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale);
try { 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 { } finally {
LocaleUtils.setSystemLocale(mResources, savedLocale); LocaleUtils.setSystemLocale(mResources, savedLocale);
} }

View file

@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard;
import android.graphics.Rect; import android.graphics.Rect;
import com.android.inputmethod.keyboard.Key; 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.SubtypeSwitcher;
import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; 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. */ /** Number of key widths from current touch point to search for nearest keys. */
private static float SEARCH_DISTANCE = 1.2f; private static float SEARCH_DISTANCE = 1.2f;
private static final int[] EMPTY_INT_ARRAY = new int[0]; 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 mKeyHeight;
private final int mGridWidth; private final int mGridWidth;
@ -46,13 +45,8 @@ public class ProximityInfo {
private final int mKeyboardHeight; private final int mKeyboardHeight;
private final int[][] mGridNeighbors; 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, ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
int keyHeight, List<Key> keys, float[] touchPositionCorrectionXs, int keyHeight, List<Key> keys, TouchPositionCorrection touchPositionCorrection) {
float[] touchPositionCorrectionYs, float[] touchPositionCorrectionRadii) {
mGridWidth = gridWidth; mGridWidth = gridWidth;
mGridHeight = gridHeight; mGridHeight = gridHeight;
mGridSize = mGridWidth * mGridHeight; mGridSize = mGridWidth * mGridHeight;
@ -61,19 +55,16 @@ public class ProximityInfo {
mKeyboardMinWidth = minWidth; mKeyboardMinWidth = minWidth;
mKeyboardHeight = height; mKeyboardHeight = height;
mKeyHeight = keyHeight; mKeyHeight = keyHeight;
mTouchPositionCorrectionXs = touchPositionCorrectionXs;
mTouchPositionCorrectionYs = touchPositionCorrectionYs;
mTouchPositionCorrectionRadii = touchPositionCorrectionRadii;
mGridNeighbors = new int[mGridSize][]; mGridNeighbors = new int[mGridSize][];
if (minWidth == 0 || height == 0) { if (minWidth == 0 || height == 0) {
// No proximity required. Keyboard might be mini keyboard. // No proximity required. Keyboard might be mini keyboard.
return; return;
} }
computeNearestNeighbors(keyWidth, keys); computeNearestNeighbors(keyWidth, keys, touchPositionCorrection);
} }
public static ProximityInfo createDummyProximityInfo() { 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() { public static ProximityInfo createSpellCheckerProximityInfo() {
@ -98,7 +89,8 @@ public class ProximityInfo {
private native void releaseProximityInfoNative(int nativeProximityInfo); private native void releaseProximityInfoNative(int nativeProximityInfo);
private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, 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]; int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE); Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE);
for (int i = 0; i < mGridSize; ++i) { for (int i = 0; i < mGridSize; ++i) {
@ -123,23 +115,16 @@ public class ProximityInfo {
keyCharCodes[i] = key.mCode; keyCharCodes[i] = key.mCode;
} }
final SubtypeSwitcher switcher = SubtypeSwitcher.getInstance(); float[] sweetSpotCenterXs = null;
final boolean hasTouchPositionCorrectionData = float[] sweetSpotCenterYs = null;
switcher.currentSubtypeContainsExtraValueKey(SUPPORT_TOUCH_POSITION_CORRECTION) float[] sweetSpotRadii = null;
&& mTouchPositionCorrectionXs != null
&& mTouchPositionCorrectionYs != null if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
&& mTouchPositionCorrectionRadii != null sweetSpotCenterXs = new float[keyCount];
&& mTouchPositionCorrectionXs.length > 0 sweetSpotCenterYs = new float[keyCount];
&& mTouchPositionCorrectionYs.length > 0 sweetSpotRadii = new float[keyCount];
&& mTouchPositionCorrectionRadii.length > 0; calculateSweetSpot(keys, touchPositionCorrection,
final float[] sweetSpotCenterXs = sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
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);
} }
mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE,
@ -148,21 +133,24 @@ public class ProximityInfo {
sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
} }
private void calculateSweetSpot(List<Key> keys, float[] sweetSpotCenterXs, private void calculateSweetSpot(List<Key> keys, TouchPositionCorrection touchPositionCorrection,
float[] sweetSpotCenterYs, float[] sweetSpotRadii) { float[] sweetSpotCenterXs, float[] sweetSpotCenterYs, float[] sweetSpotRadii) {
final int keyCount = keys.size(); 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) { for (int i = 0; i < keyCount; ++i) {
final Key key = keys.get(i); final Key key = keys.get(i);
final Rect hitBox = key.mHitBox; final Rect hitBox = key.mHitBox;
final int row = hitBox.top / mKeyHeight; 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 hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f; final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
final float hitBoxWidth = hitBox.right - hitBox.left; final float hitBoxWidth = hitBox.right - hitBox.left;
final float hitBoxHeight = hitBox.bottom - hitBox.top; final float hitBoxHeight = hitBox.bottom - hitBox.top;
final float x = mTouchPositionCorrectionXs[row]; final float x = xs[row];
final float y = mTouchPositionCorrectionYs[row]; final float y = ys[row];
final float radius = mTouchPositionCorrectionRadii[row]; final float radius = radii[row];
sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth; sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight; sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
sweetSpotRadii[i] = radius 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 thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE);
final int threshold = thresholdBase * thresholdBase; final int threshold = thresholdBase * thresholdBase;
// Round-up so we don't have any pixels outside the grid // 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; 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) { public int[] getNearestKeys(int x, int y) {

View file

@ -127,8 +127,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
private static final int DEFAULT_KEYBOARD_COLUMNS = 10; private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
private static final int DEFAULT_KEYBOARD_ROWS = 4; private static final int DEFAULT_KEYBOARD_ROWS = 4;
private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
protected final KP mParams; protected final KP mParams;
protected final Context mContext; protected final Context mContext;
protected final Resources mResources; protected final Resources mResources;
@ -254,10 +252,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
} }
private static void setTouchPositionCorrectionData(Context context, KeyboardParams params) { private static void setTouchPositionCorrectionData(Context context, KeyboardParams params) {
params.mTouchPositionCorrectionXs = null;
params.mTouchPositionCorrectionYs = null;
params.mTouchPositionCorrectionRadii = null;
final TypedArray a = context.obtainStyledAttributes( final TypedArray a = context.obtainStyledAttributes(
null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); null, R.styleable.Keyboard, R.attr.keyboardStyle, 0);
params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 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 String[] data = context.getResources().getStringArray(resourceId);
final int dataLength = data.length; params.mTouchPositionCorrection.load(data);
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;
}
} }
public KeyboardBuilder<KP> load(KeyboardId id) { public KeyboardBuilder<KP> load(KeyboardId id) {
@ -319,6 +281,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
return this; return this;
} }
public void setTouchPositionCorrectionEnabled(boolean enabled) {
mParams.mTouchPositionCorrection.setEnabled(enabled);
}
public Keyboard build() { public Keyboard build() {
return new Keyboard(mParams); return new Keyboard(mParams);
} }

View file

@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable;
import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.latin.LatinImeLogger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -68,9 +69,62 @@ public class KeyboardParams {
public int mMostCommonKeyHeight = 0; public int mMostCommonKeyHeight = 0;
public int mMostCommonKeyWidth = 0; public int mMostCommonKeyWidth = 0;
public float[] mTouchPositionCorrectionXs; public final TouchPositionCorrection mTouchPositionCorrection = new TouchPositionCorrection();
public float[] mTouchPositionCorrectionYs;
public float[] mTouchPositionCorrectionRadii; 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() { protected void clearKeys() {
mKeys.clear(); mKeys.clear();

View file

@ -117,6 +117,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
*/ */
public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable"; 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 * The subtype extra value used to indicate that the subtype keyboard layout should be loaded
* from the specified locale. * from the specified locale.