Loading java/res/values/config.xml +1 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ false --> <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool> <!-- Static threshold for gesture after fast typing (msec) --> <integer name="config_gesture_static_time_threshold_after_fast_typing">1000</integer> <integer name="config_gesture_static_time_threshold_after_fast_typing">500</integer> <!-- Static threshold for starting gesture detection (keyWidth%/sec) --> <fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction> <!-- Dynamic threshold for gesture after fast typing (msec) --> Loading java/res/values/phantom_sudden_move_event_device_list.xml→java/res/values/phantom-sudden-move-event-device-list.xml +0 −0 File moved. View file java/src/com/android/inputmethod/keyboard/PointerTracker.java +144 −35 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static final boolean DEBUG_EVENT = false; private static final boolean DEBUG_MOVE_EVENT = false; private static final boolean DEBUG_LISTENER = false; private static boolean DEBUG_MODE = LatinImeLogger.sDBG; private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; /** True if {@link PointerTracker}s should handle gesture events. */ private static boolean sShouldHandleGesture = false; Loading Loading @@ -121,8 +121,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { static final class PointerTrackerParams { public final boolean mSlidingKeyInputEnabled; public final int mTouchNoiseThresholdTime; public final float mTouchNoiseThresholdDistance; public final int mTouchNoiseThresholdDistanceSquared; public final int mTouchNoiseThresholdDistance; public final int mSuppressKeyPreviewAfterBatchInputDuration; public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); Loading @@ -130,8 +129,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private PointerTrackerParams() { mSlidingKeyInputEnabled = false; mTouchNoiseThresholdTime = 0; mTouchNoiseThresholdDistance = 0.0f; mTouchNoiseThresholdDistanceSquared = 0; mTouchNoiseThresholdDistance = 0; mSuppressKeyPreviewAfterBatchInputDuration = 0; } Loading @@ -140,11 +138,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { R.styleable.MainKeyboardView_slidingKeyInputEnable, false); mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); final float touchNouseThresholdDistance = mainKeyboardViewAttr.getDimension( mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); mTouchNoiseThresholdDistance = touchNouseThresholdDistance; mTouchNoiseThresholdDistanceSquared = (int)(touchNouseThresholdDistance * touchNouseThresholdDistance); mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); } Loading @@ -154,6 +149,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static PointerTrackerParams sParams; private static GestureStrokeParams sGestureStrokeParams; private static boolean sNeedsPhantomSuddenMoveEventHack; // Move this threshold to resource. // TODO: Device specific parameter would be better for device specific hack? private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth // This hack might be device specific. private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true; private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); private static PointerTrackerQueue sPointerTrackerQueue; Loading @@ -166,7 +166,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private KeyboardActionListener mListener = EMPTY_LISTENER; private Keyboard mKeyboard; private int mKeyQuarterWidthSquared; private int mPhantonSuddenMoveThreshold; private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); private boolean mIsDetectingGesture = false; // per PointerTracker. private static boolean sInGesture = false; Loading @@ -177,6 +178,51 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers static final class BogusMoveEventDetector { // Move these thresholds to resource. private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.70f; // in keyWidth private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.50f; // in keyWidth private int mAccumulatedDistanceThreshold; private int mRadiusThreshold; // Accumulated distance from actual and artificial down keys. /* package */ int mAccumulatedDistanceFromDownKey; private int mActualDownX; private int mActualDownY; public void setKeyboardGeometry(final int keyWidth) { mAccumulatedDistanceThreshold = (int)( keyWidth * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); mRadiusThreshold = (int)(keyWidth * BOGUS_MOVE_RADIUS_THRESHOLD); } public void onActualDownEvent(final int x, final int y) { mActualDownX = x; mActualDownY = y; } public void onDownKey() { mAccumulatedDistanceFromDownKey = 0; } public void onMoveKey(final int distance) { mAccumulatedDistanceFromDownKey += distance; } public boolean hasTraveledLongDistance() { return mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; } /* package */ int getDistanceFromDownEvent(final int x, final int y) { return getDistance(x, y, mActualDownX, mActualDownY); } public boolean isCloseToActualDownEvent(final int x, final int y) { return getDistanceFromDownEvent(x, y) < mRadiusThreshold; } } static final class TimeRecorder { private final int mSuppressKeyPreviewAfterBatchInputDuration; private final int mStaticTimeThresholdAfterFastTyping; // msec Loading @@ -192,6 +238,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; } public boolean isInFastTyping(final long eventTime) { final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; } private boolean wasLastInputTyping() { return mLastTypingTime >= mLastBatchInputTime; } Loading Loading @@ -471,8 +522,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } // Keep {@link #mCurrentKey} that comes from previous keyboard. } final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; final int keyWidth = mKeyboard.mMostCommonKeyWidth; mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); mBogusMoveEventDetector.setKeyboardGeometry(keyWidth); } @Override Loading Loading @@ -596,10 +648,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private Key onDownKey(final int x, final int y, final long eventTime) { mDownTime = eventTime; mBogusMoveEventDetector.onDownKey(); return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); } static int getDistance(final int x1, final int y1, final int x2, final int y2) { return (int)Math.hypot(x1 - x2, y1 - y2); } private Key onMoveKeyInternal(final int x, final int y) { mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); mLastX = x; mLastY = y; return mKeyDetector.detectHitKey(x, y); Loading Loading @@ -713,15 +771,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // Naive up-to-down noise filter. final long deltaT = eventTime - mUpTime; if (deltaT < sParams.mTouchNoiseThresholdTime) { final int dx = x - mLastX; final int dy = y - mLastY; final int distanceSquared = (dx * dx + dy * dy); if (distanceSquared < sParams.mTouchNoiseThresholdDistanceSquared) { final int distance = getDistance(x, y, mLastX, mLastY); if (distance < sParams.mTouchNoiseThresholdDistance) { if (DEBUG_MODE) Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT + " distance=" + distanceSquared); Log.w(TAG, String.format("[%d] onDownEvent:" + " ignore potential noise: time=%d distance=%d", mPointerId, deltaT, distance)); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_onDownEvent(deltaT, distanceSquared); ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); } mKeyAlreadyProcessed = true; return; Loading @@ -729,6 +786,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final Key key = getKeyOn(x, y); mBogusMoveEventDetector.onActualDownEvent(x, y); final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { if (key != null && key.isModifier()) { Loading Loading @@ -856,7 +914,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { onMoveToNewKey(key, x, y); startLongPressTimer(key); setPressedKeyGraphics(key, eventTime); } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) { } else if (isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) { // The pointer has been slid in to the new key from the previous key, we must call // onRelease() first to notify that the previous key has been released, then call // onPress() to notify that the new key is being pressed. Loading @@ -876,20 +934,19 @@ public final class PointerTracker implements PointerTrackerQueue.Element { startLongPressTimer(key); setPressedKeyGraphics(key, eventTime); } else { // HACK: On some devices, quick successive touches may be translated to sudden // move by touch panel firmware. This hack detects the case and translates the // HACK: On some devices, quick successive touches may be reported as a sudden // move by touch panel firmware. This hack detects such cases and translates the // move event to successive up and down events. final int dx = x - lastX; final int dy = y - lastY; final int lastMoveSquared = dx * dx + dy * dy; // TODO: Should find a way to balance gesture detection and this hack. if (sNeedsPhantomSuddenMoveEventHack && lastMoveSquared >= mKeyQuarterWidthSquared && !mIsDetectingGesture) { && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { if (DEBUG_MODE) { Log.w(TAG, String.format("onMoveEvent:" + " phantom sudden move event is translated to " + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); Log.w(TAG, String.format("[%d] onMoveEvent:" + " phantom sudden move event (distance=%d) is translated to " + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, getDistance(x, y, lastX, lastY), lastX, lastY, Keyboard.printableCode(oldKey.mCode), x, y, Keyboard.printableCode(key.mCode))); } // TODO: This should be moved to outside of this nested if-clause? if (ProductionFlag.IS_EXPERIMENTAL) { Loading @@ -897,6 +954,26 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } onUpEventInternal(eventTime); onDownEventInternal(x, y, eventTime); } // HACK: On some devices, quick successive proximate touches may be reported as // a bogus down-move-up event by touch panel firmware. This hack detects such // cases and breaks these events into separate up and down events. else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { if (DEBUG_MODE) { final float radiusRatio = (float)mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) / mKeyboard.mMostCommonKeyWidth; Log.w(TAG, String.format("[%d] onMoveEvent:" + " bogus down-move-up event (raidus=%.2f keyWidth) is " + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, radiusRatio, lastX, lastY, Keyboard.printableCode(oldKey.mCode), x, y, Keyboard.printableCode(key.mCode))); } onUpEventInternal(eventTime); onDownEventInternal(x, y, eventTime); } else { // HACK: If there are currently multiple touches, register the key even if // the finger slides off the key. This defends against noise from some Loading @@ -905,7 +982,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // this hack. if (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { onUpEventInternal(eventTime); if (DEBUG_MODE) { Log.w(TAG, String.format("[%d] onMoveEvent:" + " detected sliding finger while multi touching", mPointerId)); } onUpEvent(x, y, eventTime); mKeyAlreadyProcessed = true; } if (!mIsDetectingGesture) { mKeyAlreadyProcessed = true; Loading @@ -915,7 +998,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } } else { if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, key)) { if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) { // The pointer has been slid out from the previous key, we must call onRelease() to // notify that the previous key has been released. setReleasedKeyGraphics(oldKey); Loading Loading @@ -1049,7 +1132,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final Key newKey) { private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, final Key newKey) { if (mKeyDetector == null) { throw new NullPointerException("keyboard and/or key detector not set"); } Loading @@ -1059,8 +1143,33 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } else if (curKey != null) { final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( mIsInSlidingKeyInputFromModifier); return curKey.squaredDistanceToEdge(x, y) >= keyHysteresisDistanceSquared; } else { final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { if (DEBUG_MODE) { final int keyWidth = mKeyboard.mMostCommonKeyWidth; final float distanceToEdgeRatio = (float)distanceFromKeyEdgeSquared / (keyWidth * keyWidth); Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" +" %.2f keyWidth from key edge", mPointerId, distanceToEdgeRatio)); } return true; } if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput && sTimeRecorder.isInFastTyping(eventTime) && mBogusMoveEventDetector.hasTraveledLongDistance()) { if (DEBUG_MODE) { final float lengthFromDownRatio = (float)mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / mKeyboard.mMostCommonKeyWidth; Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" + " %.2f keyWidth from virtual down point", mPointerId, lengthFromDownRatio)); } return true; } return false; } else { // curKey == null && newKey != null return true; } } Loading Loading
java/res/values/config.xml +1 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ false --> <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool> <!-- Static threshold for gesture after fast typing (msec) --> <integer name="config_gesture_static_time_threshold_after_fast_typing">1000</integer> <integer name="config_gesture_static_time_threshold_after_fast_typing">500</integer> <!-- Static threshold for starting gesture detection (keyWidth%/sec) --> <fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction> <!-- Dynamic threshold for gesture after fast typing (msec) --> Loading
java/res/values/phantom_sudden_move_event_device_list.xml→java/res/values/phantom-sudden-move-event-device-list.xml +0 −0 File moved. View file
java/src/com/android/inputmethod/keyboard/PointerTracker.java +144 −35 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static final boolean DEBUG_EVENT = false; private static final boolean DEBUG_MOVE_EVENT = false; private static final boolean DEBUG_LISTENER = false; private static boolean DEBUG_MODE = LatinImeLogger.sDBG; private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; /** True if {@link PointerTracker}s should handle gesture events. */ private static boolean sShouldHandleGesture = false; Loading Loading @@ -121,8 +121,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { static final class PointerTrackerParams { public final boolean mSlidingKeyInputEnabled; public final int mTouchNoiseThresholdTime; public final float mTouchNoiseThresholdDistance; public final int mTouchNoiseThresholdDistanceSquared; public final int mTouchNoiseThresholdDistance; public final int mSuppressKeyPreviewAfterBatchInputDuration; public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); Loading @@ -130,8 +129,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private PointerTrackerParams() { mSlidingKeyInputEnabled = false; mTouchNoiseThresholdTime = 0; mTouchNoiseThresholdDistance = 0.0f; mTouchNoiseThresholdDistanceSquared = 0; mTouchNoiseThresholdDistance = 0; mSuppressKeyPreviewAfterBatchInputDuration = 0; } Loading @@ -140,11 +138,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { R.styleable.MainKeyboardView_slidingKeyInputEnable, false); mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); final float touchNouseThresholdDistance = mainKeyboardViewAttr.getDimension( mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); mTouchNoiseThresholdDistance = touchNouseThresholdDistance; mTouchNoiseThresholdDistanceSquared = (int)(touchNouseThresholdDistance * touchNouseThresholdDistance); mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); } Loading @@ -154,6 +149,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static PointerTrackerParams sParams; private static GestureStrokeParams sGestureStrokeParams; private static boolean sNeedsPhantomSuddenMoveEventHack; // Move this threshold to resource. // TODO: Device specific parameter would be better for device specific hack? private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth // This hack might be device specific. private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true; private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); private static PointerTrackerQueue sPointerTrackerQueue; Loading @@ -166,7 +166,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private KeyboardActionListener mListener = EMPTY_LISTENER; private Keyboard mKeyboard; private int mKeyQuarterWidthSquared; private int mPhantonSuddenMoveThreshold; private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); private boolean mIsDetectingGesture = false; // per PointerTracker. private static boolean sInGesture = false; Loading @@ -177,6 +178,51 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers static final class BogusMoveEventDetector { // Move these thresholds to resource. private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.70f; // in keyWidth private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.50f; // in keyWidth private int mAccumulatedDistanceThreshold; private int mRadiusThreshold; // Accumulated distance from actual and artificial down keys. /* package */ int mAccumulatedDistanceFromDownKey; private int mActualDownX; private int mActualDownY; public void setKeyboardGeometry(final int keyWidth) { mAccumulatedDistanceThreshold = (int)( keyWidth * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); mRadiusThreshold = (int)(keyWidth * BOGUS_MOVE_RADIUS_THRESHOLD); } public void onActualDownEvent(final int x, final int y) { mActualDownX = x; mActualDownY = y; } public void onDownKey() { mAccumulatedDistanceFromDownKey = 0; } public void onMoveKey(final int distance) { mAccumulatedDistanceFromDownKey += distance; } public boolean hasTraveledLongDistance() { return mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; } /* package */ int getDistanceFromDownEvent(final int x, final int y) { return getDistance(x, y, mActualDownX, mActualDownY); } public boolean isCloseToActualDownEvent(final int x, final int y) { return getDistanceFromDownEvent(x, y) < mRadiusThreshold; } } static final class TimeRecorder { private final int mSuppressKeyPreviewAfterBatchInputDuration; private final int mStaticTimeThresholdAfterFastTyping; // msec Loading @@ -192,6 +238,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; } public boolean isInFastTyping(final long eventTime) { final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; } private boolean wasLastInputTyping() { return mLastTypingTime >= mLastBatchInputTime; } Loading Loading @@ -471,8 +522,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } // Keep {@link #mCurrentKey} that comes from previous keyboard. } final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; final int keyWidth = mKeyboard.mMostCommonKeyWidth; mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); mBogusMoveEventDetector.setKeyboardGeometry(keyWidth); } @Override Loading Loading @@ -596,10 +648,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private Key onDownKey(final int x, final int y, final long eventTime) { mDownTime = eventTime; mBogusMoveEventDetector.onDownKey(); return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); } static int getDistance(final int x1, final int y1, final int x2, final int y2) { return (int)Math.hypot(x1 - x2, y1 - y2); } private Key onMoveKeyInternal(final int x, final int y) { mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); mLastX = x; mLastY = y; return mKeyDetector.detectHitKey(x, y); Loading Loading @@ -713,15 +771,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // Naive up-to-down noise filter. final long deltaT = eventTime - mUpTime; if (deltaT < sParams.mTouchNoiseThresholdTime) { final int dx = x - mLastX; final int dy = y - mLastY; final int distanceSquared = (dx * dx + dy * dy); if (distanceSquared < sParams.mTouchNoiseThresholdDistanceSquared) { final int distance = getDistance(x, y, mLastX, mLastY); if (distance < sParams.mTouchNoiseThresholdDistance) { if (DEBUG_MODE) Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT + " distance=" + distanceSquared); Log.w(TAG, String.format("[%d] onDownEvent:" + " ignore potential noise: time=%d distance=%d", mPointerId, deltaT, distance)); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_onDownEvent(deltaT, distanceSquared); ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); } mKeyAlreadyProcessed = true; return; Loading @@ -729,6 +786,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final Key key = getKeyOn(x, y); mBogusMoveEventDetector.onActualDownEvent(x, y); final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { if (key != null && key.isModifier()) { Loading Loading @@ -856,7 +914,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { onMoveToNewKey(key, x, y); startLongPressTimer(key); setPressedKeyGraphics(key, eventTime); } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) { } else if (isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) { // The pointer has been slid in to the new key from the previous key, we must call // onRelease() first to notify that the previous key has been released, then call // onPress() to notify that the new key is being pressed. Loading @@ -876,20 +934,19 @@ public final class PointerTracker implements PointerTrackerQueue.Element { startLongPressTimer(key); setPressedKeyGraphics(key, eventTime); } else { // HACK: On some devices, quick successive touches may be translated to sudden // move by touch panel firmware. This hack detects the case and translates the // HACK: On some devices, quick successive touches may be reported as a sudden // move by touch panel firmware. This hack detects such cases and translates the // move event to successive up and down events. final int dx = x - lastX; final int dy = y - lastY; final int lastMoveSquared = dx * dx + dy * dy; // TODO: Should find a way to balance gesture detection and this hack. if (sNeedsPhantomSuddenMoveEventHack && lastMoveSquared >= mKeyQuarterWidthSquared && !mIsDetectingGesture) { && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { if (DEBUG_MODE) { Log.w(TAG, String.format("onMoveEvent:" + " phantom sudden move event is translated to " + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); Log.w(TAG, String.format("[%d] onMoveEvent:" + " phantom sudden move event (distance=%d) is translated to " + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, getDistance(x, y, lastX, lastY), lastX, lastY, Keyboard.printableCode(oldKey.mCode), x, y, Keyboard.printableCode(key.mCode))); } // TODO: This should be moved to outside of this nested if-clause? if (ProductionFlag.IS_EXPERIMENTAL) { Loading @@ -897,6 +954,26 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } onUpEventInternal(eventTime); onDownEventInternal(x, y, eventTime); } // HACK: On some devices, quick successive proximate touches may be reported as // a bogus down-move-up event by touch panel firmware. This hack detects such // cases and breaks these events into separate up and down events. else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { if (DEBUG_MODE) { final float radiusRatio = (float)mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) / mKeyboard.mMostCommonKeyWidth; Log.w(TAG, String.format("[%d] onMoveEvent:" + " bogus down-move-up event (raidus=%.2f keyWidth) is " + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, radiusRatio, lastX, lastY, Keyboard.printableCode(oldKey.mCode), x, y, Keyboard.printableCode(key.mCode))); } onUpEventInternal(eventTime); onDownEventInternal(x, y, eventTime); } else { // HACK: If there are currently multiple touches, register the key even if // the finger slides off the key. This defends against noise from some Loading @@ -905,7 +982,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element { // this hack. if (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { onUpEventInternal(eventTime); if (DEBUG_MODE) { Log.w(TAG, String.format("[%d] onMoveEvent:" + " detected sliding finger while multi touching", mPointerId)); } onUpEvent(x, y, eventTime); mKeyAlreadyProcessed = true; } if (!mIsDetectingGesture) { mKeyAlreadyProcessed = true; Loading @@ -915,7 +998,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } } else { if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, key)) { if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) { // The pointer has been slid out from the previous key, we must call onRelease() to // notify that the previous key has been released. setReleasedKeyGraphics(oldKey); Loading Loading @@ -1049,7 +1132,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final Key newKey) { private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, final Key newKey) { if (mKeyDetector == null) { throw new NullPointerException("keyboard and/or key detector not set"); } Loading @@ -1059,8 +1143,33 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } else if (curKey != null) { final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( mIsInSlidingKeyInputFromModifier); return curKey.squaredDistanceToEdge(x, y) >= keyHysteresisDistanceSquared; } else { final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { if (DEBUG_MODE) { final int keyWidth = mKeyboard.mMostCommonKeyWidth; final float distanceToEdgeRatio = (float)distanceFromKeyEdgeSquared / (keyWidth * keyWidth); Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" +" %.2f keyWidth from key edge", mPointerId, distanceToEdgeRatio)); } return true; } if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput && sTimeRecorder.isInFastTyping(eventTime) && mBogusMoveEventDetector.hasTraveledLongDistance()) { if (DEBUG_MODE) { final float lengthFromDownRatio = (float)mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / mKeyboard.mMostCommonKeyWidth; Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" + " %.2f keyWidth from virtual down point", mPointerId, lengthFromDownRatio)); } return true; } return false; } else { // curKey == null && newKey != null return true; } } Loading