From 0fef498a07515bdd5ac1ccfa564776d72fd85a51 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Tue, 30 Mar 2010 16:49:15 -0700 Subject: [PATCH] Treat fast moves as multi-touch. Bug: 2561786 Detect sudden moves that have a large delta that would not be a typical drag by the user when hunting for a key. Drop move events until the user releases the touch and register both starting and ending keys instead of only the ending key. This reduces the frequency of dropped keys on touch hardware that isn't able to detect multi-touch reliably. This also takes into account diagonal moves or right angled moves due to pseudo-multi-touch. It weakens the swipe gestures (to swipe, you'll need to swipe slowly and fully, otherwise it will trigger 2 keys) Change-Id: Ieba3a0bef4c8910f0f17aa20baedb3581d1de12b --- .../inputmethod/latin/LatinKeyboardView.java | 114 +++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java index d0c6bc648..1e90dccab 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java @@ -44,10 +44,25 @@ public class LatinKeyboardView extends KeyboardView { private Keyboard mPhoneKeyboard; + /** Whether the extension of this keyboard is visible */ private boolean mExtensionVisible; + /** The view that is shown as an extension of this keyboard view */ private LatinKeyboardView mExtension; + /** The popup window that contains the extension of this keyboard */ private PopupWindow mExtensionPopup; + /** Whether this view is an extension of another keyboard */ + private boolean mIsExtensionType; private boolean mFirstEvent; + /** Whether we've started dropping move events because we found a big jump */ + private boolean mDroppingEvents; + /** + * Whether multi-touch disambiguation needs to be disabled for any reason. There are 2 reasons + * for this to happen - (1) if a real multi-touch event has occured and (2) we've opened an + * extension keyboard. + */ + private boolean mDisableDisambiguation; + /** The distance threshold at which we start treating the touch session as a multi-touch */ + private int mJumpThresholdSquare = Integer.MAX_VALUE; public LatinKeyboardView(Context context, AttributeSet attrs) { super(context, attrs); @@ -61,6 +76,15 @@ public class LatinKeyboardView extends KeyboardView { mPhoneKeyboard = phoneKeyboard; } + @Override + public void setKeyboard(Keyboard k) { + super.setKeyboard(k); + // One-seventh of the keyboard width seems like a reasonable threshold + mJumpThresholdSquare = k.getMinWidth() / 7; + mJumpThresholdSquare *= mJumpThresholdSquare; + setKeyboardLocal(k); + } + @Override protected boolean onLongPress(Key key) { if (key.codes[0] == Keyboard.KEYCODE_MODE_CHANGE) { @@ -79,6 +103,79 @@ public class LatinKeyboardView extends KeyboardView { } } + /** + * This function checks to see if we need to handle any sudden jumps in the pointer location + * that could be due to a multi-touch being treated as a move by the firmware or hardware. + * Once a sudden jump is detected, all subsequent move events are discarded + * until an UP is received.

+ * When a sudden jump is detected, an UP event is simulated at the last position and when + * the sudden moves subside, a DOWN event is simulated for the second key. + * @param me the motion event + * @return true if the event was consumed, so that it doesn't continue to be handled by + * KeyboardView. + */ + private boolean handleSuddenJump(MotionEvent me) { + final int action = me.getAction(); + final int x = (int) me.getX(); + final int y = (int) me.getY(); + boolean result = false; + + // Real multi-touch event? Stop looking for sudden jumps + if (me.getPointerCount() > 1) { + mDisableDisambiguation = true; + } + if (mDisableDisambiguation) { + // If UP, reset the multi-touch flag + if (action == MotionEvent.ACTION_UP) mDisableDisambiguation = false; + return false; + } + + switch (action) { + case MotionEvent.ACTION_DOWN: + // Reset the "session" + mDroppingEvents = false; + mDisableDisambiguation = false; + break; + case MotionEvent.ACTION_MOVE: + // Is this a big jump? + final int distanceSquare = (mLastX - x) * (mLastX - x) + (mLastY - y) * (mLastY - y); + if (distanceSquare > mJumpThresholdSquare) { + // If we're not yet dropping events, start dropping and send an UP event + if (!mDroppingEvents) { + mDroppingEvents = true; + // Send an up event + MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), + MotionEvent.ACTION_UP, + mLastX, mLastY, me.getMetaState()); + super.onTouchEvent(translated); + translated.recycle(); + } + result = true; + } else if (mDroppingEvents) { + // If moves are small and we're already dropping events, continue dropping + result = true; + } + break; + case MotionEvent.ACTION_UP: + if (mDroppingEvents) { + // Send a down event first, as we dropped a bunch of sudden jumps and assume that + // the user is releasing the touch on the second key. + MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), + MotionEvent.ACTION_DOWN, + x, y, me.getMetaState()); + super.onTouchEvent(translated); + translated.recycle(); + mDroppingEvents = false; + // Let the up event get processed as well, result = false + } + break; + } + // Track the previous coordinate + mLastX = x; + mLastY = y; + return result; + } + @Override public boolean onTouchEvent(MotionEvent me) { LatinKeyboard keyboard = (LatinKeyboard) getKeyboard(); @@ -87,6 +184,12 @@ public class LatinKeyboardView extends KeyboardView { mLastY = (int) me.getY(); invalidate(); } + // If an extension keyboard is visible or this is an extension keyboard, don't look + // for sudden jumps. Otherwise, if there was a sudden jump, return without processing the + // actual motion event. + if (!mExtensionVisible && !mIsExtensionType + && handleSuddenJump(me)) return true; + // Reset any bounding box controls in the keyboard if (me.getAction() == MotionEvent.ACTION_DOWN) { keyboard.keyReleased(); @@ -140,6 +243,8 @@ public class LatinKeyboardView extends KeyboardView { } else { mFirstEvent = true; } + // Stop processing multi-touch errors + mDisableDisambiguation = true; } return true; } @@ -158,6 +263,10 @@ public class LatinKeyboardView extends KeyboardView { } } + private void setExtensionType(boolean isExtensionType) { + mIsExtensionType = isExtensionType; + } + private boolean openExtension() { if (((LatinKeyboard) getKeyboard()).getExtension() == 0) return false; makePopupWindow(); @@ -173,6 +282,7 @@ public class LatinKeyboardView extends KeyboardView { LayoutInflater li = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); mExtension = (LatinKeyboardView) li.inflate(R.layout.input_trans, null); + mExtension.setExtensionType(true); mExtension.setOnKeyboardActionListener( new ExtensionKeyboardListener(getOnKeyboardActionListener())); mExtension.setPopupParent(this); @@ -258,9 +368,7 @@ public class LatinKeyboardView extends KeyboardView { private int mLastY; private Paint mPaint; - @Override - public void setKeyboard(Keyboard k) { - super.setKeyboard(k); + private void setKeyboardLocal(Keyboard k) { if (DEBUG_AUTO_PLAY) { findKeys(); if (mHandler2 == null) {