diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml index 043f4b363..15f356db9 100644 --- a/java/res/values-land/dimens.xml +++ b/java/res/values-land/dimens.xml @@ -28,8 +28,8 @@ 63dip 2dip - - 0.459in + + 0.324in -0.270in diff --git a/java/res/values-xlarge/dimens.xml b/java/res/values-xlarge/dimens.xml index a60d604cf..72110ca83 100644 --- a/java/res/values-xlarge/dimens.xml +++ b/java/res/values-xlarge/dimens.xml @@ -28,8 +28,8 @@ 0.720in - - 0.765in + + 0.540in -0.450in diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index a2ce3648d..5267f3b40 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -28,8 +28,8 @@ 80sp - - 0.553in + + 0.390in -0.325in diff --git a/java/src/com/android/inputmethod/latin/BaseKeyboard.java b/java/src/com/android/inputmethod/latin/BaseKeyboard.java index 266300eb3..e5b2756d4 100644 --- a/java/src/com/android/inputmethod/latin/BaseKeyboard.java +++ b/java/src/com/android/inputmethod/latin/BaseKeyboard.java @@ -24,7 +24,6 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.text.TextUtils; -import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.util.Xml; @@ -109,15 +108,16 @@ public class BaseKeyboard { // Variables for pre-computing nearest keys. - private final int GRID_WIDTH; - private final int GRID_HEIGHT; + public final int GRID_WIDTH; + public final int GRID_HEIGHT; private final int GRID_SIZE; private int mCellWidth; private int mCellHeight; private int[][] mGridNeighbors; private int mProximityThreshold; + private static int[] EMPTY_INT_ARRAY = new int[0]; /** Number of key widths from current touch point to search for nearest keys. */ - private static float SEARCH_DISTANCE = 1.8f; + private static float SEARCH_DISTANCE = 1.2f; /** * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. @@ -402,18 +402,21 @@ public class BaseKeyboard { } /** - * Returns the square of the distance between the center of the key and the given point. + * Returns the square of the distance to the nearest edge of the key and the given point. * @param x the x-coordinate of the point * @param y the y-coordinate of the point - * @return the square of the distance of the point from the center of the key + * @return the square of the distance of the point from the nearest edge of the key */ - public int squaredDistanceFrom(int x, int y) { - // We should count vertical gap between rows to calculate the center of this Key. - // TODO: We should re-think how we define the center of the key. - final int verticalGap = keyboard.getVerticalGap(); - int xDist = this.x + width / 2 - x; - int yDist = this.y + (height + verticalGap) / 2 - y; - return xDist * xDist + yDist * yDist; + public int squaredDistanceToEdge(int x, int y) { + final int left = this.x; + final int right = left + this.width; + final int top = this.y; + final int bottom = top + this.height; + final int edgeX = x < left ? left : (x > right ? right : x); + final int edgeY = y < top ? top : (y > bottom ? bottom : y); + final int dx = x - edgeX; + final int dy = y - edgeY; + return dx * dx + dy * dy; } /** @@ -633,24 +636,21 @@ public class BaseKeyboard { mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH; mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT; mGridNeighbors = new int[GRID_SIZE][]; - int[] indices = new int[mKeys.size()]; + final int[] indices = new int[mKeys.size()]; final int gridWidth = GRID_WIDTH * mCellWidth; final int gridHeight = GRID_HEIGHT * mCellHeight; + final int threshold = mProximityThreshold; for (int x = 0; x < gridWidth; x += mCellWidth) { for (int y = 0; y < gridHeight; y += mCellHeight) { + final int centerX = x + mCellWidth / 2; + final int centerY = y + mCellHeight / 2; int count = 0; for (int i = 0; i < mKeys.size(); i++) { final Key key = mKeys.get(i); - final int threshold = mProximityThreshold; - if (key.squaredDistanceFrom(x, y) < threshold || - key.squaredDistanceFrom(x + mCellWidth - 1, y) < threshold || - key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1) - < threshold || - key.squaredDistanceFrom(x, y + mCellHeight - 1) < threshold) { + if (key.squaredDistanceToEdge(centerX, centerY) < threshold) indices[count++] = i; - } } - int [] cell = new int[count]; + final int[] cell = new int[count]; System.arraycopy(indices, 0, cell, 0, count); mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell; } @@ -672,7 +672,7 @@ public class BaseKeyboard { return mGridNeighbors[index]; } } - return new int[0]; + return EMPTY_INT_ARRAY; } // TODO should be private diff --git a/java/src/com/android/inputmethod/latin/BaseKeyboardView.java b/java/src/com/android/inputmethod/latin/BaseKeyboardView.java index 4ba6fbddc..070d031e7 100644 --- a/java/src/com/android/inputmethod/latin/BaseKeyboardView.java +++ b/java/src/com/android/inputmethod/latin/BaseKeyboardView.java @@ -71,6 +71,7 @@ import java.util.WeakHashMap; public class BaseKeyboardView extends View implements PointerTracker.UIProxy { private static final String TAG = "BaseKeyboardView"; private static final boolean DEBUG = false; + private static final boolean DEBUG_KEYBOARD_GRID = false; public static final int NOT_A_TOUCH_COORDINATE = -1; @@ -183,8 +184,6 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy { // Main keyboard private BaseKeyboard mKeyboard; private Key[] mKeys; - // TODO this attribute should be gotten from Keyboard. - private int mKeyboardVerticalGap; // Key preview popup private boolean mInForeground; @@ -609,7 +608,6 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy { LatinImeLogger.onSetKeyboard(keyboard); mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); - mKeyboardVerticalGap = (int)getResources().getDimension(R.dimen.key_bottom_gap); for (PointerTracker tracker : mPointerTrackers) { tracker.setKeyboard(keyboard, mKeys, mKeyHysteresisDistance); } @@ -617,7 +615,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy { // Hint to reallocate the buffer if the size changed mKeyboardChanged = true; invalidateAllKeys(); - computeProximityThreshold(keyboard); + computeProximityThreshold(keyboard, mKeys); mMiniKeyboardCache.clear(); } @@ -713,23 +711,27 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy { } /** - * Compute the average distance between adjacent keys (horizontally and vertically) - * and square it to get the proximity threshold. We use a square here and in computing - * the touch distance from a key's center to avoid taking a square root. + * Compute the most common key width and use it as proximity key detection threshold. * @param keyboard + * @param keys */ - private void computeProximityThreshold(BaseKeyboard keyboard) { - if (keyboard == null) return; - final Key[] keys = mKeys; - if (keys == null) return; - int length = keys.length; - int dimensionSum = 0; - for (int i = 0; i < length; i++) { - Key key = keys[i]; - dimensionSum += Math.min(key.width, key.height + mKeyboardVerticalGap) + key.gap; + private void computeProximityThreshold(BaseKeyboard keyboard, Key[] keys) { + if (keyboard == null || keys == null || keys.length == 0) return; + final HashMap histogram = new HashMap(); + int maxCount = 0; + int mostCommonWidth = 0; + for (Key key : keys) { + final Integer width = key.width + key.gap; + Integer count = histogram.get(width); + if (count == null) + count = 0; + histogram.put(width, ++count); + if (count > maxCount) { + maxCount = count; + mostCommonWidth = width; + } } - if (dimensionSum < 0 || length == 0) return; - mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length)); + mKeyDetector.setProximityThreshold(mostCommonWidth); } @Override @@ -868,6 +870,20 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy { } canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); } + + if (DEBUG_KEYBOARD_GRID) { + Paint p = new Paint(); + p.setStyle(Paint.Style.STROKE); + p.setStrokeWidth(1.0f); + p.setColor(0x800000c0); + int cw = (mKeyboard.getMinWidth() + mKeyboard.GRID_WIDTH - 1) / mKeyboard.GRID_WIDTH; + int ch = (mKeyboard.getHeight() + mKeyboard.GRID_HEIGHT - 1) / mKeyboard.GRID_HEIGHT; + for (int i = 0; i <= mKeyboard.GRID_WIDTH; i++) + canvas.drawLine(i * cw, 0, i * cw, ch * mKeyboard.GRID_HEIGHT, p); + for (int i = 0; i <= mKeyboard.GRID_HEIGHT; i++) + canvas.drawLine(0, i * ch, cw * mKeyboard.GRID_WIDTH, i * ch, p); + } + mInvalidatedKey = null; // Overlay a dark rectangle to dim the keyboard if (mMiniKeyboard != null) { diff --git a/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java index 0e0c2e7fc..3cc43b99c 100644 --- a/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java +++ b/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java @@ -41,17 +41,18 @@ class MiniKeyboardKeyDetector extends KeyDetector { final Key[] keys = getKeys(); final int touchX = getTouchX(x); final int touchY = getTouchY(y); + int closestKeyIndex = BaseKeyboardView.NOT_A_KEY; int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; final int keyCount = keys.length; - for (int i = 0; i < keyCount; i++) { - final Key key = keys[i]; - int dist = key.squaredDistanceFrom(touchX, touchY); + for (int index = 0; index < keyCount; index++) { + final int dist = keys[index].squaredDistanceToEdge(touchX, touchY); if (dist < closestKeyDist) { - closestKeyIndex = i; + closestKeyIndex = index; closestKeyDist = dist; } } + if (allKeys != null && closestKeyIndex != BaseKeyboardView.NOT_A_KEY) allKeys[0] = keys[closestKeyIndex].codes[0]; return closestKeyIndex; diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java index 78e00720a..2194ed91b 100644 --- a/java/src/com/android/inputmethod/latin/PointerTracker.java +++ b/java/src/com/android/inputmethod/latin/PointerTracker.java @@ -396,24 +396,12 @@ public class PointerTracker { if (newKey == curKey) { return true; } else if (isValidKeyIndex(curKey)) { - return getSquareDistanceToKeyEdge(x, y, mKeys[curKey]) < mKeyHysteresisDistanceSquared; + return mKeys[curKey].squaredDistanceToEdge(x, y) < mKeyHysteresisDistanceSquared; } else { return false; } } - private static int getSquareDistanceToKeyEdge(int x, int y, Key key) { - final int left = key.x; - final int right = key.x + key.width; - final int top = key.y; - final int bottom = key.y + key.height; - final int edgeX = x < left ? left : (x > right ? right : x); - final int edgeY = y < top ? top : (y > bottom ? bottom : y); - final int dx = x - edgeX; - final int dy = y - edgeY; - return dx * dx + dy * dy; - } - private void showKeyPreviewAndUpdateKeyGraphics(int keyIndex) { updateKeyGraphics(keyIndex); // The modifier key, such as shift key, should not be shown as preview when multi-touch is diff --git a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java index 01122ebb7..35bdc6728 100644 --- a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java +++ b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java @@ -36,41 +36,34 @@ class ProximityKeyDetector extends KeyDetector { final Key[] keys = getKeys(); final int touchX = getTouchX(x); final int touchY = getTouchY(y); - int primaryIndex = BaseKeyboardView.NOT_A_KEY; - int closestKey = BaseKeyboardView.NOT_A_KEY; - int closestKeyDist = mProximityThresholdSquare + 1; - int[] distances = mDistances; - Arrays.fill(distances, Integer.MAX_VALUE); - int [] nearestKeyIndices = mKeyboard.getNearestKeys(touchX, touchY); - final int keyCount = nearestKeyIndices.length; - for (int i = 0; i < keyCount; i++) { - final Key key = keys[nearestKeyIndices[i]]; - int dist = 0; - boolean isInside = key.isInside(touchX, touchY); - if (isInside) { - primaryIndex = nearestKeyIndices[i]; - } - if (((mProximityCorrectOn - && (dist = key.squaredDistanceFrom(touchX, touchY)) < mProximityThresholdSquare) - || isInside) - && key.codes[0] > 32) { - // Find insertion point - final int nCodes = key.codes.length; + int primaryIndex = BaseKeyboardView.NOT_A_KEY; + int closestKeyIndex = BaseKeyboardView.NOT_A_KEY; + int closestKeyDist = mProximityThresholdSquare + 1; + final int[] distances = mDistances; + Arrays.fill(distances, Integer.MAX_VALUE); + for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) { + final Key key = keys[index]; + final boolean isInside = key.isInside(touchX, touchY); + if (isInside) + primaryIndex = index; + final int dist = key.squaredDistanceToEdge(touchX, touchY); + if (isInside || (mProximityCorrectOn && dist < mProximityThresholdSquare)) { if (dist < closestKeyDist) { closestKeyDist = dist; - closestKey = nearestKeyIndices[i]; + closestKeyIndex = index; } if (allKeys == null) continue; - + final int nCodes = key.codes.length; + // Find insertion point for (int j = 0; j < distances.length; j++) { if (distances[j] > dist) { // Make space for nCodes codes System.arraycopy(distances, j, distances, j + nCodes, - distances.length - j - nCodes); + distances.length - (j + nCodes)); System.arraycopy(allKeys, j, allKeys, j + nCodes, - allKeys.length - j - nCodes); + allKeys.length - (j + nCodes)); System.arraycopy(key.codes, 0, allKeys, j, nCodes); Arrays.fill(distances, j, j + nCodes, dist); break; @@ -78,9 +71,7 @@ class ProximityKeyDetector extends KeyDetector { } } } - if (primaryIndex == BaseKeyboardView.NOT_A_KEY) { - primaryIndex = closestKey; - } - return primaryIndex; + + return primaryIndex == BaseKeyboardView.NOT_A_KEY ? closestKeyIndex : primaryIndex; } }