diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java index 346daa3e3..ee9b6bb69 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java @@ -43,7 +43,6 @@ import android.view.ViewGroup.LayoutParams; import android.widget.PopupWindow; import android.widget.TextView; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -143,7 +142,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener public static final int NOT_A_TOUCH_COORDINATE = -1; private static final boolean DEBUG = false; - private static final int NOT_A_KEY = -1; + static final int NOT_A_KEY = -1; private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable }; @@ -184,7 +183,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener private static final int DEBOUNCE_TIME = 70; private int mVerticalCorrection; - private int mProximityThreshold; + private ProximityKeyDetector mProximityKeyDetector = new ProximityKeyDetector(); private boolean mPreviewCentered = false; private boolean mShowPreview = true; @@ -193,13 +192,10 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener private int mPopupPreviewY; private int mWindowY; - private boolean mProximityCorrectOn; - private Paint mPaint; private Rect mPadding; private int mCurrentKey = NOT_A_KEY; - private int mDownKey = NOT_A_KEY; private int mStartX; private int mStartY; @@ -227,9 +223,6 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener private static final int REPEAT_START_DELAY = 400; private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); - private static int MAX_NEARBY_KEYS = 12; - private int[] mDistances = new int[MAX_NEARBY_KEYS]; - // For multi-tap private int mLastSentIndex; private int mTapCount; @@ -625,6 +618,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener LatinImeLogger.onSetKeyboard(mKeyboard); List keys = mKeyboard.getKeys(); mKeys = keys.toArray(new Key[keys.size()]); + mProximityKeyDetector.setKeyboard(keyboard, mKeys); requestLayout(); // Hint to reallocate the buffer if the size changed mKeyboardChanged = true; @@ -719,14 +713,14 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener * @param enabled whether or not the proximity correction is enabled */ public void setProximityCorrectionEnabled(boolean enabled) { - mProximityCorrectOn = enabled; + mProximityKeyDetector.setProximityCorrectionEnabled(enabled); } /** * Returns true if proximity correction is enabled. */ public boolean isProximityCorrectionEnabled() { - return mProximityCorrectOn; + return mProximityKeyDetector.isProximityCorrectionEnabled(); } /** @@ -778,8 +772,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener dimensionSum += Math.min(key.width, key.height) + key.gap; } if (dimensionSum < 0 || length == 0) return; - mProximityThreshold = (int) (dimensionSum * 1.4f / length); - mProximityThreshold *= mProximityThreshold; // Square it + mProximityKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length)); final float hysteresisPixel = getContext().getResources() .getDimension(R.dimen.key_debounce_hysteresis_distance); @@ -920,54 +913,6 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener mDirtyRect.setEmpty(); } - private int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) { - final Key[] keys = mKeys; - int primaryIndex = NOT_A_KEY; - int closestKey = NOT_A_KEY; - int closestKeyDist = mProximityThreshold + 1; - Arrays.fill(mDistances, Integer.MAX_VALUE); - int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); - 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(x,y); - if (isInside) { - primaryIndex = nearestKeyIndices[i]; - } - - if (((mProximityCorrectOn - && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) - || isInside) - && key.codes[0] > 32) { - // Find insertion point - final int nCodes = key.codes.length; - if (dist < closestKeyDist) { - closestKeyDist = dist; - closestKey = nearestKeyIndices[i]; - } - - if (allKeys == null) continue; - - for (int j = 0; j < mDistances.length; j++) { - if (mDistances[j] > dist) { - // Make space for nCodes codes - System.arraycopy(mDistances, j, mDistances, j + nCodes, - mDistances.length - j - nCodes); - System.arraycopy(allKeys, j, allKeys, j + nCodes, - allKeys.length - j - nCodes); - System.arraycopy(key.codes, 0, allKeys, j, nCodes); - Arrays.fill(mDistances, j, j + nCodes, dist); - break; - } - } - } - } - if (primaryIndex == NOT_A_KEY) { - primaryIndex = closestKey; - } - return primaryIndex; - } private void detectAndSendKey(int index, int x, int y, long eventTime) { if (index != NOT_A_KEY && index < mKeys.length) { @@ -978,9 +923,8 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } else { int code = key.codes[0]; //TextEntryState.keyPressedAt(key, x, y); - int[] codes = new int[MAX_NEARBY_KEYS]; - Arrays.fill(codes, NOT_A_KEY); - getKeyIndexAndNearbyCodes(x, y, codes); + int[] codes = mProximityKeyDetector.newCodeArray(); + mProximityKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); // Multi-tap if (mInMultiTap) { if (mTapCount != -1) { @@ -1352,13 +1296,12 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener int touchY = (int) me.getY() + mVerticalCorrection - getPaddingTop(); final int action = me.getAction(); final long eventTime = me.getEventTime(); - int keyIndex = getKeyIndexAndNearbyCodes(touchX, touchY, null); + int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); switch (action) { case MotionEvent.ACTION_DOWN: mAbortKey = false; mCurrentKey = keyIndex; - mDownKey = keyIndex; mStartX = touchX; mStartY = touchY; mDebouncer.startMoveDebouncing(touchX, touchY); diff --git a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java new file mode 100644 index 000000000..eae2d7f08 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; + +import java.util.Arrays; + +class ProximityKeyDetector { + private static final int MAX_NEARBY_KEYS = 12; + + private Keyboard mKeyboard; + private Key[] mKeys; + + private boolean mProximityCorrectOn; + private int mProximityThresholdSquare; + + // working area + private int[] mDistances = new int[MAX_NEARBY_KEYS]; + + public void setKeyboard(Keyboard keyboard, Key[] keys) { + if (keyboard == null || keys == null) + throw new NullPointerException(); + mKeyboard = keyboard; + mKeys = keys; + } + + public void setProximityCorrectionEnabled(boolean enabled) { + mProximityCorrectOn = enabled; + } + + public boolean isProximityCorrectionEnabled() { + return mProximityCorrectOn; + } + + public void setProximityThreshold(int threshold) { + mProximityThresholdSquare = threshold * threshold; + } + + public int[] newCodeArray() { + int[] codes = new int[MAX_NEARBY_KEYS]; + Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY); + return codes; + } + + public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) { + final Key[] keys = mKeys; + if (keys == null) + throw new IllegalStateException("keyboard isn't set"); + // mKeyboard is guaranteed not null at setKeybaord() method + int primaryIndex = LatinKeyboardBaseView.NOT_A_KEY; + int closestKey = LatinKeyboardBaseView.NOT_A_KEY; + int closestKeyDist = mProximityThresholdSquare + 1; + int[] distances = mDistances; + Arrays.fill(distances, Integer.MAX_VALUE); + int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); + 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(x,y); + if (isInside) { + primaryIndex = nearestKeyIndices[i]; + } + + if (((mProximityCorrectOn + && (dist = key.squaredDistanceFrom(x, y)) < mProximityThresholdSquare) + || isInside) + && key.codes[0] > 32) { + // Find insertion point + final int nCodes = key.codes.length; + if (dist < closestKeyDist) { + closestKeyDist = dist; + closestKey = nearestKeyIndices[i]; + } + + if (allKeys == null) continue; + + 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); + System.arraycopy(allKeys, j, allKeys, j + nCodes, + allKeys.length - j - nCodes); + System.arraycopy(key.codes, 0, allKeys, j, nCodes); + Arrays.fill(distances, j, j + nCodes, dist); + break; + } + } + } + } + if (primaryIndex == LatinKeyboardBaseView.NOT_A_KEY) { + primaryIndex = closestKey; + } + return primaryIndex; + } +} \ No newline at end of file