From dc90d0a15f662cdece97bc2c0ddbd95e703af730 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 15 Apr 2011 13:05:58 +0900 Subject: [PATCH] Refactoring keyboard drawing code and KeyDetector Change-Id: I55009bf38b1422301223bd90463f837562559dc5 --- .../inputmethod/keyboard/KeyDetector.java | 138 ++++++-- .../inputmethod/keyboard/KeyboardView.java | 294 +++++++++--------- .../keyboard/MiniKeyboardKeyDetector.java | 15 +- .../inputmethod/keyboard/PointerTracker.java | 35 +-- .../keyboard/ProximityKeyDetector.java | 124 -------- .../inputmethod/latin/SuggestHelper.java | 5 +- 6 files changed, 287 insertions(+), 324 deletions(-) delete mode 100644 java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index bf0fb9a89..95ec93181 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -16,35 +16,35 @@ package com.android.inputmethod.keyboard; +import android.util.Log; + import java.util.Arrays; import java.util.List; -public abstract class KeyDetector { - public static final int NOT_A_KEY = -1; +public class KeyDetector { + private static final String TAG = KeyDetector.class.getSimpleName(); + private static final boolean DEBUG = false; + public static final int NOT_A_CODE = -1; + public static final int NOT_A_KEY = -1; - protected Keyboard mKeyboard; + private Keyboard mKeyboard; + private int mCorrectionX; + private int mCorrectionY; + private boolean mProximityCorrectOn; + private int mProximityThresholdSquare; - private Key[] mKeys; + // working area + private static final int MAX_NEARBY_KEYS = 12; + private final int[] mDistances = new int[MAX_NEARBY_KEYS]; + private final int[] mIndices = new int[MAX_NEARBY_KEYS]; - protected int mCorrectionX; - - protected int mCorrectionY; - - protected boolean mProximityCorrectOn; - - protected int mProximityThresholdSquare; - - public Key[] setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { + public void setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { if (keyboard == null) throw new NullPointerException(); mCorrectionX = (int)correctionX; mCorrectionY = (int)correctionY; mKeyboard = keyboard; - List keys = mKeyboard.getKeys(); - Key[] array = keys.toArray(new Key[keys.size()]); - mKeys = array; - return array; } protected int getTouchX(int x) { @@ -55,11 +55,11 @@ public abstract class KeyDetector { return y + mCorrectionY; } - protected Key[] getKeys() { - if (mKeys == null) + protected List getKeys() { + if (mKeyboard == null) throw new IllegalStateException("keyboard isn't set"); // mKeyboard is guaranteed not to be null at setKeybaord() method if mKeys is not null - return mKeys; + return mKeyboard.getKeys(); } public void setProximityCorrectionEnabled(boolean enabled) { @@ -74,6 +74,17 @@ public abstract class KeyDetector { mProximityThresholdSquare = threshold * threshold; } + /** + * Computes maximum size of the array that can contain all nearby key indices returned by + * {@link #getKeyIndexAndNearbyCodes}. + * + * @return Returns maximum size of the array that can contain all nearby key indices returned + * by {@link #getKeyIndexAndNearbyCodes}. + */ + protected int getMaxNearbyKeys() { + return MAX_NEARBY_KEYS; + } + /** * Allocates array that can hold all key indices returned by {@link #getKeyIndexAndNearbyCodes} * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. @@ -88,14 +99,60 @@ public abstract class KeyDetector { return codes; } + private void initializeNearbyKeys() { + Arrays.fill(mDistances, Integer.MAX_VALUE); + Arrays.fill(mIndices, NOT_A_KEY); + } + /** - * Computes maximum size of the array that can contain all nearby key indices returned by - * {@link #getKeyIndexAndNearbyCodes}. + * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance. * - * @return Returns maximum size of the array that can contain all nearby key indices returned - * by {@link #getKeyIndexAndNearbyCodes}. + * @param keyIndex index of the key. + * @param distance distance between the key's edge and user touched point. + * @return order of the key in the nearby buffer, 0 if it is the nearest key. */ - abstract protected int getMaxNearbyKeys(); + private int sortNearbyKeys(int keyIndex, int distance) { + final int[] distances = mDistances; + final int[] indices = mIndices; + for (int insertPos = 0; insertPos < distances.length; insertPos++) { + if (distance < distances[insertPos]) { + final int nextPos = insertPos + 1; + if (nextPos < distances.length) { + System.arraycopy(distances, insertPos, distances, nextPos, + distances.length - nextPos); + System.arraycopy(indices, insertPos, indices, nextPos, + indices.length - nextPos); + } + distances[insertPos] = distance; + indices[insertPos] = keyIndex; + return insertPos; + } + } + return distances.length; + } + + private void getNearbyKeyCodes(final int[] allCodes) { + final List keys = getKeys(); + final int[] indices = mIndices; + + // allCodes[0] should always have the key code even if it is a non-letter key. + if (indices[0] == NOT_A_KEY) { + allCodes[0] = NOT_A_CODE; + return; + } + + int numCodes = 0; + for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) { + final int index = indices[j]; + if (index == NOT_A_KEY) + break; + final int code = keys.get(index).mCode; + // filter out a non-letter key from nearby keys + if (code < Keyboard.CODE_SPACE) + continue; + allCodes[numCodes++] = code; + } + } /** * Finds all possible nearby key indices around a touch event point and returns the nearest key @@ -108,5 +165,34 @@ public abstract class KeyDetector { * @param allCodes All nearby key code except functional key are returned in this array * @return The nearest key index */ - abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes); + public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { + final List keys = getKeys(); + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); + + initializeNearbyKeys(); + int primaryIndex = NOT_A_KEY; + for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) { + final Key key = keys.get(index); + final boolean isInside = key.isInside(touchX, touchY); + final int distance = key.squaredDistanceToEdge(touchX, touchY); + if (isInside || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { + final int insertedPosition = sortNearbyKeys(index, distance); + if (insertedPosition == 0 && isInside) + primaryIndex = index; + } + } + + if (allCodes != null && allCodes.length > 0) { + getNearbyKeyCodes(allCodes); + if (DEBUG) { + Log.d(TAG, "x=" + x + " y=" + y + + " primary=" + + (primaryIndex == NOT_A_KEY ? "none" : keys.get(primaryIndex).mCode) + + " codes=" + Arrays.toString(allCodes)); + } + } + + return primaryIndex; + } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 1e19a8ad4..a140a974d 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -106,7 +106,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Main keyboard private Keyboard mKeyboard; - private Key[] mKeys; // Key preview popup private boolean mInForeground; @@ -147,7 +146,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Accessibility private boolean mIsAccessibilityEnabled; - protected KeyDetector mKeyDetector = new ProximityKeyDetector(); + protected KeyDetector mKeyDetector = new KeyDetector(); // Swipe gesture detector private GestureDetector mGestureDetector; @@ -493,10 +492,10 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mHandler.cancelPopupPreview(); mKeyboard = keyboard; LatinImeLogger.onSetKeyboard(keyboard); - mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), + mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); for (PointerTracker tracker : mPointerTrackers) { - tracker.setKeyboard(keyboard, mKeys, mKeyHysteresisDistance); + tracker.setKeyboard(keyboard, mKeyHysteresisDistance); } requestLayout(); mKeyboardChanged = true; @@ -638,154 +637,32 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } final Canvas canvas = mCanvas; canvas.clipRect(mDirtyRect, Op.REPLACE); + canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); if (mKeyboard == null) return; - final Paint paint = mPaint; - final Drawable keyBackground = mKeyBackground; - final Rect padding = mPadding; - final int kbdPaddingLeft = getPaddingLeft(); - final int kbdPaddingTop = getPaddingTop(); - final Key[] keys = mKeys; - final boolean isManualTemporaryUpperCase = mKeyboard.isManualTemporaryUpperCase(); - final boolean drawSingleKey = (mInvalidatedKey != null - && mInvalidatedKeyRect.contains(mDirtyRect)); - - canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); - final int keyCount = keys.length; - for (int i = 0; i < keyCount; i++) { - final Key key = keys[i]; - if (drawSingleKey && key != mInvalidatedKey) { - continue; + if (mInvalidatedKey != null && mInvalidatedKeyRect.contains(mDirtyRect)) { + // Draw a single key. + onBufferDrawKey(canvas, mInvalidatedKey); + } else { + // Draw all keys. + for (final Key key : mKeyboard.getKeys()) { + onBufferDrawKey(canvas, key); } - int[] drawableState = key.getCurrentDrawableState(); - keyBackground.setState(drawableState); - - // Switch the character to uppercase if shift is pressed - String label = key.mLabel == null? null : adjustCase(key.mLabel).toString(); - - final int keyDrawX = key.mX + key.mVisualInsetsLeft; - final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight; - final Rect bounds = keyBackground.getBounds(); - if (keyDrawWidth != bounds.right || key.mHeight != bounds.bottom) { - keyBackground.setBounds(0, 0, keyDrawWidth, key.mHeight); - } - canvas.translate(keyDrawX + kbdPaddingLeft, key.mY + kbdPaddingTop); - keyBackground.draw(canvas); - - final int rowHeight = padding.top + key.mHeight; - // Draw key label - if (label != null) { - // For characters, use large font. For labels like "Done", use small font. - final int labelSize = getLabelSizeAndSetPaint(label, key.mLabelOption, paint); - final int labelCharHeight = getLabelCharHeight(labelSize, paint); - - // Vertical label text alignment. - final float baseline; - if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_BOTTOM) != 0) { - baseline = key.mHeight - - + labelCharHeight * KEY_LABEL_VERTICAL_PADDING_FACTOR; - if (DEBUG_SHOW_ALIGN) - drawHorizontalLine(canvas, (int)baseline, keyDrawWidth, 0xc0008000, - new Paint()); - } else { // Align center - final float centerY = (key.mHeight + padding.top - padding.bottom) / 2; - baseline = centerY - + labelCharHeight * KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR_CENTER; - if (DEBUG_SHOW_ALIGN) - drawHorizontalLine(canvas, (int)baseline, keyDrawWidth, 0xc0008000, - new Paint()); - } - // Horizontal label text alignment - final int positionX; - if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_LEFT) != 0) { - positionX = mKeyLabelHorizontalPadding + padding.left; - paint.setTextAlign(Align.LEFT); - if (DEBUG_SHOW_ALIGN) - drawVerticalLine(canvas, positionX, rowHeight, 0xc0800080, new Paint()); - } else if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_RIGHT) != 0) { - positionX = keyDrawWidth - mKeyLabelHorizontalPadding - padding.right; - paint.setTextAlign(Align.RIGHT); - if (DEBUG_SHOW_ALIGN) - drawVerticalLine(canvas, positionX, rowHeight, 0xc0808000, new Paint()); - } else { - positionX = (keyDrawWidth + padding.left - padding.right) / 2; - paint.setTextAlign(Align.CENTER); - if (DEBUG_SHOW_ALIGN) { - if (label.length() > 1) - drawVerticalLine(canvas, positionX, rowHeight, 0xc0008080, new Paint()); - } - } - if (key.mManualTemporaryUpperCaseHintIcon != null && isManualTemporaryUpperCase) { - paint.setColor(mKeyTextColorDisabled); - } else { - paint.setColor(mKeyTextColor); - } - if (key.mEnabled) { - // Set a drop shadow for the text - paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); - } else { - // Make label invisible - paint.setColor(Color.TRANSPARENT); - } - canvas.drawText(label, positionX, baseline, paint); - // Turn off drop shadow - paint.setShadowLayer(0, 0, 0, 0); - } - // Draw key icon - final Drawable icon = key.getIcon(); - if (key.mLabel == null && icon != null) { - final int drawableWidth = icon.getIntrinsicWidth(); - final int drawableHeight = icon.getIntrinsicHeight(); - final int drawableX; - final int drawableY = ( - key.mHeight + padding.top - padding.bottom - drawableHeight) / 2; - if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_LEFT) != 0) { - drawableX = padding.left + mKeyLabelHorizontalPadding; - if (DEBUG_SHOW_ALIGN) - drawVerticalLine(canvas, drawableX, rowHeight, 0xc0800080, new Paint()); - } else if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_RIGHT) != 0) { - drawableX = keyDrawWidth - padding.right - mKeyLabelHorizontalPadding - - drawableWidth; - if (DEBUG_SHOW_ALIGN) - drawVerticalLine(canvas, drawableX + drawableWidth, rowHeight, - 0xc0808000, new Paint()); - } else { // Align center - drawableX = (keyDrawWidth + padding.left - padding.right - drawableWidth) / 2; - if (DEBUG_SHOW_ALIGN) - drawVerticalLine(canvas, drawableX + drawableWidth / 2, rowHeight, - 0xc0008080, new Paint()); - } - drawIcon(canvas, icon, drawableX, drawableY, drawableWidth, drawableHeight); - if (DEBUG_SHOW_ALIGN) - drawRectangle(canvas, drawableX, drawableY, drawableWidth, drawableHeight, - 0x80c00000, new Paint()); - } - if (key.mHintIcon != null) { - final int drawableWidth = keyDrawWidth; - final int drawableHeight = key.mHeight; - final int drawableX = 0; - final int drawableY = HINT_ICON_VERTICAL_ADJUSTMENT_PIXEL; - Drawable hintIcon = (isManualTemporaryUpperCase - && key.mManualTemporaryUpperCaseHintIcon != null) - ? key.mManualTemporaryUpperCaseHintIcon : key.mHintIcon; - drawIcon(canvas, hintIcon, drawableX, drawableY, drawableWidth, drawableHeight); - if (DEBUG_SHOW_ALIGN) - drawRectangle(canvas, drawableX, drawableY, drawableWidth, drawableHeight, - 0x80c0c000, new Paint()); - } - canvas.translate(-keyDrawX - kbdPaddingLeft, -key.mY - kbdPaddingTop); } - // TODO: Move this function to ProximityInfo for getting rid of public declarations for + // TODO: Move this function to ProximityInfo for getting rid of + // public declarations for // GRID_WIDTH and GRID_HEIGHT 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; + 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++) @@ -794,8 +671,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Overlay a dark rectangle to dim the keyboard if (mMiniKeyboardView != null) { - paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); - canvas.drawRect(0, 0, width, height, paint); + mPaint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); + canvas.drawRect(0, 0, width, height, mPaint); } mInvalidatedKey = null; @@ -803,6 +680,134 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mDirtyRect.setEmpty(); } + private void onBufferDrawKey(final Canvas canvas, final Key key) { + final Paint paint = mPaint; + final Drawable keyBackground = mKeyBackground; + final Rect padding = mPadding; + final int kbdPaddingLeft = getPaddingLeft(); + final int kbdPaddingTop = getPaddingTop(); + final int keyDrawX = key.mX + key.mVisualInsetsLeft; + final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight; + final int rowHeight = padding.top + key.mHeight; + final boolean isManualTemporaryUpperCase = mKeyboard.isManualTemporaryUpperCase(); + + canvas.translate(keyDrawX + kbdPaddingLeft, key.mY + kbdPaddingTop); + + // Draw key background. + final int[] drawableState = key.getCurrentDrawableState(); + keyBackground.setState(drawableState); + final Rect bounds = keyBackground.getBounds(); + if (keyDrawWidth != bounds.right || key.mHeight != bounds.bottom) { + keyBackground.setBounds(0, 0, keyDrawWidth, key.mHeight); + } + keyBackground.draw(canvas); + + // Draw key label. + if (key.mLabel != null) { + // Switch the character to uppercase if shift is pressed + final String label = key.mLabel == null ? null : adjustCase(key.mLabel).toString(); + // For characters, use large font. For labels like "Done", use small font. + final int labelSize = getLabelSizeAndSetPaint(label, key.mLabelOption, paint); + final int labelCharHeight = getLabelCharHeight(labelSize, paint); + + // Vertical label text alignment. + final float baseline; + if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_BOTTOM) != 0) { + baseline = key.mHeight - labelCharHeight * KEY_LABEL_VERTICAL_PADDING_FACTOR; + if (DEBUG_SHOW_ALIGN) + drawHorizontalLine(canvas, (int)baseline, keyDrawWidth, 0xc0008000, + new Paint()); + } else { // Align center + final float centerY = (key.mHeight + padding.top - padding.bottom) / 2; + baseline = centerY + labelCharHeight * KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR_CENTER; + if (DEBUG_SHOW_ALIGN) + drawHorizontalLine(canvas, (int)baseline, keyDrawWidth, 0xc0008000, + new Paint()); + } + // Horizontal label text alignment + final int positionX; + if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_LEFT) != 0) { + positionX = mKeyLabelHorizontalPadding + padding.left; + paint.setTextAlign(Align.LEFT); + if (DEBUG_SHOW_ALIGN) + drawVerticalLine(canvas, positionX, rowHeight, 0xc0800080, new Paint()); + } else if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_RIGHT) != 0) { + positionX = keyDrawWidth - mKeyLabelHorizontalPadding - padding.right; + paint.setTextAlign(Align.RIGHT); + if (DEBUG_SHOW_ALIGN) + drawVerticalLine(canvas, positionX, rowHeight, 0xc0808000, new Paint()); + } else { + positionX = (keyDrawWidth + padding.left - padding.right) / 2; + paint.setTextAlign(Align.CENTER); + if (DEBUG_SHOW_ALIGN) { + if (label.length() > 1) + drawVerticalLine(canvas, positionX, rowHeight, 0xc0008080, new Paint()); + } + } + if (key.mManualTemporaryUpperCaseHintIcon != null && isManualTemporaryUpperCase) { + paint.setColor(mKeyTextColorDisabled); + } else { + paint.setColor(mKeyTextColor); + } + if (key.mEnabled) { + // Set a drop shadow for the text + paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); + } else { + // Make label invisible + paint.setColor(Color.TRANSPARENT); + } + canvas.drawText(label, positionX, baseline, paint); + // Turn off drop shadow + paint.setShadowLayer(0, 0, 0, 0); + } + + // Draw key icon. + final Drawable icon = key.getIcon(); + if (key.mLabel == null && icon != null) { + final int drawableWidth = icon.getIntrinsicWidth(); + final int drawableHeight = icon.getIntrinsicHeight(); + final int drawableX; + final int drawableY = (key.mHeight + padding.top - padding.bottom - drawableHeight) / 2; + if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_LEFT) != 0) { + drawableX = padding.left + mKeyLabelHorizontalPadding; + if (DEBUG_SHOW_ALIGN) + drawVerticalLine(canvas, drawableX, rowHeight, 0xc0800080, new Paint()); + } else if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_RIGHT) != 0) { + drawableX = keyDrawWidth - padding.right - mKeyLabelHorizontalPadding + - drawableWidth; + if (DEBUG_SHOW_ALIGN) + drawVerticalLine(canvas, drawableX + drawableWidth, rowHeight, + 0xc0808000, new Paint()); + } else { // Align center + drawableX = (keyDrawWidth + padding.left - padding.right - drawableWidth) / 2; + if (DEBUG_SHOW_ALIGN) + drawVerticalLine(canvas, drawableX + drawableWidth / 2, rowHeight, + 0xc0008080, new Paint()); + } + drawIcon(canvas, icon, drawableX, drawableY, drawableWidth, drawableHeight); + if (DEBUG_SHOW_ALIGN) + drawRectangle(canvas, drawableX, drawableY, drawableWidth, drawableHeight, + 0x80c00000, new Paint()); + } + + // Draw hint icon. + if (key.mHintIcon != null) { + final int drawableWidth = keyDrawWidth; + final int drawableHeight = key.mHeight; + final int drawableX = 0; + final int drawableY = HINT_ICON_VERTICAL_ADJUSTMENT_PIXEL; + Drawable hintIcon = (isManualTemporaryUpperCase + && key.mManualTemporaryUpperCaseHintIcon != null) + ? key.mManualTemporaryUpperCaseHintIcon : key.mHintIcon; + drawIcon(canvas, hintIcon, drawableX, drawableY, drawableWidth, drawableHeight); + if (DEBUG_SHOW_ALIGN) + drawRectangle(canvas, drawableX, drawableY, drawableWidth, drawableHeight, + 0x80c0c000, new Paint()); + } + + canvas.translate(-keyDrawX - kbdPaddingLeft, -key.mY - kbdPaddingTop); + } + public int getLabelSizeAndSetPaint(CharSequence label, int keyLabelOption, Paint paint) { // For characters, use large font. For labels like "Done", use small font. final int labelSize; @@ -1179,15 +1184,14 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private PointerTracker getPointerTracker(final int id) { final ArrayList pointers = mPointerTrackers; - final Key[] keys = mKeys; final KeyboardActionListener listener = mKeyboardActionListener; // Create pointer trackers until we can get 'id+1'-th tracker, if needed. for (int i = pointers.size(); i <= id; i++) { final PointerTracker tracker = new PointerTracker(i, mHandler, mKeyDetector, this, getResources()); - if (keys != null) - tracker.setKeyboard(mKeyboard, keys, mKeyHysteresisDistance); + if (mKeyboard != null) + tracker.setKeyboard(mKeyboard, mKeyHysteresisDistance); if (listener != null) tracker.setOnKeyboardActionListener(listener); pointers.add(tracker); diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java index a8750d378..c4459f616 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java @@ -16,9 +16,9 @@ package com.android.inputmethod.keyboard; -public class MiniKeyboardKeyDetector extends KeyDetector { - private static final int MAX_NEARBY_KEYS = 1; +import java.util.List; +public class MiniKeyboardKeyDetector extends KeyDetector { private final int mSlideAllowanceSquare; private final int mSlideAllowanceSquareTop; @@ -31,20 +31,21 @@ public class MiniKeyboardKeyDetector extends KeyDetector { @Override protected int getMaxNearbyKeys() { - return MAX_NEARBY_KEYS; + // No nearby key will be returned. + return 1; } @Override public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { - final Key[] keys = getKeys(); + final List keys = getKeys(); final int touchX = getTouchX(x); final int touchY = getTouchY(y); int nearestIndex = NOT_A_KEY; int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - final int keyCount = keys.length; + final int keyCount = keys.size(); for (int index = 0; index < keyCount; index++) { - final int dist = keys[index].squaredDistanceToEdge(touchX, touchY); + final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY); if (dist < nearestDist) { nearestIndex = index; nearestDist = dist; @@ -52,7 +53,7 @@ public class MiniKeyboardKeyDetector extends KeyDetector { } if (allCodes != null && nearestIndex != NOT_A_KEY) - allCodes[0] = keys[nearestIndex].mCode; + allCodes[0] = keys.get(nearestIndex).mCode; return nearestIndex; } } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index add38cf45..5d137b9f6 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -25,6 +25,7 @@ import android.util.Log; import android.view.MotionEvent; import java.util.Arrays; +import java.util.List; public class PointerTracker { private static final String TAG = PointerTracker.class.getSimpleName(); @@ -63,7 +64,7 @@ public class PointerTracker { private final int mTouchNoiseThresholdDistanceSquared; private Keyboard mKeyboard; - private Key[] mKeys; + private List mKeys; private int mKeyHysteresisDistanceSquared = -1; private int mKeyQuarterWidthSquared; @@ -109,8 +110,8 @@ public class PointerTracker { public void onSwipeDown() {} }; - public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, UIProxy proxy, - Resources res) { + public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, + UIProxy proxy, Resources res) { if (proxy == null || handler == null || keyDetector == null) throw new NullPointerException(); mPointerId = id; @@ -197,11 +198,11 @@ public class PointerTracker { mListener.onCancelInput(); } - public void setKeyboard(Keyboard keyboard, Key[] keys, float keyHysteresisDistance) { - if (keyboard == null || keys == null || keyHysteresisDistance < 0) + public void setKeyboard(Keyboard keyboard, float keyHysteresisDistance) { + if (keyboard == null || keyHysteresisDistance < 0) throw new IllegalArgumentException(); mKeyboard = keyboard; - mKeys = keys; + mKeys = keyboard.getKeys(); mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); final int keyQuarterWidth = keyboard.getKeyWidth() / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; @@ -214,11 +215,11 @@ public class PointerTracker { } private boolean isValidKeyIndex(int keyIndex) { - return keyIndex >= 0 && keyIndex < mKeys.length; + return keyIndex >= 0 && keyIndex < mKeys.size(); } public Key getKey(int keyIndex) { - return isValidKeyIndex(keyIndex) ? mKeys[keyIndex] : null; + return isValidKeyIndex(keyIndex) ? mKeys.get(keyIndex) : null; } private static boolean isModifierCode(int primaryCode) { @@ -258,12 +259,14 @@ public class PointerTracker { mPreviousKey = keyIndex; if (keyIndex != oldKeyIndex) { if (isValidKeyIndex(oldKeyIndex)) { - mKeys[oldKeyIndex].onReleased(); - mProxy.invalidateKey(mKeys[oldKeyIndex]); + final Key oldKey = mKeys.get(oldKeyIndex); + oldKey.onReleased(); + mProxy.invalidateKey(oldKey); } if (isValidKeyIndex(keyIndex)) { - mKeys[keyIndex].onPressed(); - mProxy.invalidateKey(mKeys[keyIndex]); + final Key newKey = mKeys.get(keyIndex); + newKey.onPressed(); + mProxy.invalidateKey(newKey); } } } @@ -488,9 +491,6 @@ public class PointerTracker { if (!mIsRepeatableKey) { detectAndSendKey(keyIndex, x, y); } - - if (isValidKeyIndex(keyIndex)) - mProxy.invalidateKey(mKeys[keyIndex]); } public void onCancelEvent(int x, int y, long eventTime, PointerTrackerQueue queue) { @@ -508,9 +508,6 @@ public class PointerTracker { mHandler.cancelPopupPreview(); showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY); mIsInSlidingKeyInput = false; - int keyIndex = mKeyState.getKeyIndex(); - if (isValidKeyIndex(keyIndex)) - mProxy.invalidateKey(mKeys[keyIndex]); } public void repeatKey(int keyIndex) { @@ -539,7 +536,7 @@ public class PointerTracker { if (newKey == curKey) { return true; } else if (isValidKeyIndex(curKey)) { - return mKeys[curKey].squaredDistanceToEdge(x, y) < mKeyHysteresisDistanceSquared; + return mKeys.get(curKey).squaredDistanceToEdge(x, y) < mKeyHysteresisDistanceSquared; } else { return false; } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java deleted file mode 100644 index c3fd1984b..000000000 --- a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.keyboard; - -import android.util.Log; - -import java.util.Arrays; - -public class ProximityKeyDetector extends KeyDetector { - private static final String TAG = ProximityKeyDetector.class.getSimpleName(); - private static final boolean DEBUG = false; - - private static final int MAX_NEARBY_KEYS = 12; - - // working area - private final int[] mDistances = new int[MAX_NEARBY_KEYS]; - private final int[] mIndices = new int[MAX_NEARBY_KEYS]; - - @Override - protected int getMaxNearbyKeys() { - return MAX_NEARBY_KEYS; - } - - private void initializeNearbyKeys() { - Arrays.fill(mDistances, Integer.MAX_VALUE); - Arrays.fill(mIndices, NOT_A_KEY); - } - - /** - * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance. - * - * @param keyIndex index of the key. - * @param distance distance between the key's edge and user touched point. - * @return order of the key in the nearby buffer, 0 if it is the nearest key. - */ - private int sortNearbyKeys(int keyIndex, int distance) { - final int[] distances = mDistances; - final int[] indices = mIndices; - for (int insertPos = 0; insertPos < distances.length; insertPos++) { - if (distance < distances[insertPos]) { - final int nextPos = insertPos + 1; - if (nextPos < distances.length) { - System.arraycopy(distances, insertPos, distances, nextPos, - distances.length - nextPos); - System.arraycopy(indices, insertPos, indices, nextPos, - indices.length - nextPos); - } - distances[insertPos] = distance; - indices[insertPos] = keyIndex; - return insertPos; - } - } - return distances.length; - } - - private void getNearbyKeyCodes(final int[] allCodes) { - final Key[] keys = getKeys(); - final int[] indices = mIndices; - - // allCodes[0] should always have the key code even if it is a non-letter key. - if (indices[0] == NOT_A_KEY) { - allCodes[0] = NOT_A_CODE; - return; - } - - int numCodes = 0; - for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) { - final int index = indices[j]; - if (index == NOT_A_KEY) - break; - final int code = keys[index].mCode; - // filter out a non-letter key from nearby keys - if (code < Keyboard.CODE_SPACE) - continue; - allCodes[numCodes++] = code; - } - } - - @Override - public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { - final Key[] keys = getKeys(); - final int touchX = getTouchX(x); - final int touchY = getTouchY(y); - - initializeNearbyKeys(); - int primaryIndex = NOT_A_KEY; - for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) { - final Key key = keys[index]; - final boolean isInside = key.isInside(touchX, touchY); - final int distance = key.squaredDistanceToEdge(touchX, touchY); - if (isInside || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { - final int insertedPosition = sortNearbyKeys(index, distance); - if (insertedPosition == 0 && isInside) - primaryIndex = index; - } - } - - if (allCodes != null && allCodes.length > 0) { - getNearbyKeyCodes(allCodes); - if (DEBUG) { - Log.d(TAG, "x=" + x + " y=" + y - + " primary=" - + (primaryIndex == NOT_A_KEY ? "none" : keys[primaryIndex].mCode) - + " codes=" + Arrays.toString(allCodes)); - } - } - - return primaryIndex; - } -} diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index 5d1ab706a..4a357a6f2 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -20,7 +20,6 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.LatinKeyboard; -import com.android.inputmethod.keyboard.ProximityKeyDetector; import android.content.Context; import android.text.TextUtils; @@ -38,7 +37,7 @@ public class SuggestHelper { // (and not try to find a dictionary provider for a specified locale) mSuggest = new Suggest(context, dictionaryId, null); mKeyboard = new LatinKeyboard(context, keyboardId); - mKeyDetector = new ProximityKeyDetector(); + mKeyDetector = new KeyDetector(); init(); } @@ -46,7 +45,7 @@ public class SuggestHelper { KeyboardId keyboardId) { mSuggest = new Suggest(dictionaryPath, startOffset, length, null); mKeyboard = new LatinKeyboard(context, keyboardId); - mKeyDetector = new ProximityKeyDetector(); + mKeyDetector = new KeyDetector(); init(); }