aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/keyboard/PointerTracker.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/keyboard/PointerTracker.java')
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java714
1 files changed, 446 insertions, 268 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 03d610a39..c86805232 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -23,9 +23,11 @@ import android.view.MotionEvent;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.keyboard.internal.GestureStroke;
+import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams;
import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
@@ -34,12 +36,12 @@ import com.android.inputmethod.research.ResearchLogger;
import java.util.ArrayList;
-public class PointerTracker implements PointerTrackerQueue.Element {
+public final class PointerTracker implements PointerTrackerQueue.Element {
private static final String TAG = PointerTracker.class.getSimpleName();
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;
@@ -117,40 +119,45 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
}
- static class PointerTrackerParams {
+ 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();
private PointerTrackerParams() {
mSlidingKeyInputEnabled = false;
mTouchNoiseThresholdTime = 0;
- mTouchNoiseThresholdDistance = 0.0f;
- mTouchNoiseThresholdDistanceSquared = 0;
+ mTouchNoiseThresholdDistance = 0;
+ mSuppressKeyPreviewAfterBatchInputDuration = 0;
}
- public PointerTrackerParams(TypedArray mainKeyboardViewAttr) {
+ public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean(
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);
}
}
// Parameters for pointer handling.
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;
+ private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue();
public final int mPointerId;
@@ -160,15 +167,126 @@ public 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;
private static long sGestureFirstDownTime;
+ private static TimeRecorder sTimeRecorder;
private static final InputPointers sAggregratedPointers = new InputPointers(
GestureStroke.DEFAULT_CAPACITY);
- private static int sLastRecognitionPointSize = 0;
- private static long sLastRecognitionTime = 0;
+ 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.
+ // These thresholds' unit is a diagonal length of a key.
+ private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f;
+ private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f;
+
+ 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, final int keyHeight) {
+ final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight);
+ mAccumulatedDistanceThreshold = (int)(
+ keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD);
+ mRadiusThreshold = (int)(keyDiagonal * 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(final int x, final int y) {
+ final int dx = Math.abs(x - mActualDownX);
+ final int dy = Math.abs(y - mActualDownY);
+ // A bogus move event should be a horizontal movement. A vertical movement might be
+ // a sloppy typing and should be ignored.
+ return dx >= dy && 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
+ private long mLastTypingTime;
+ private long mLastLetterTypingTime;
+ private long mLastBatchInputTime;
+
+ public TimeRecorder(final PointerTrackerParams pointerTrackerParams,
+ final GestureStrokeParams gestureStrokeParams) {
+ mSuppressKeyPreviewAfterBatchInputDuration =
+ pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration;
+ mStaticTimeThresholdAfterFastTyping =
+ gestureStrokeParams.mStaticTimeThresholdAfterFastTyping;
+ }
+
+ public boolean isInFastTyping(final long eventTime) {
+ final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime;
+ return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping;
+ }
+
+ private boolean wasLastInputTyping() {
+ return mLastTypingTime >= mLastBatchInputTime;
+ }
+
+ public void onCodeInput(final int code, final long eventTime) {
+ // Record the letter typing time when
+ // 1. Letter keys are typed successively without any batch input in between.
+ // 2. A letter key is typed within the threshold time since the last any key typing.
+ // 3. A non-letter key is typed within the threshold time since the last letter key
+ // typing.
+ if (Character.isLetter(code)) {
+ if (wasLastInputTyping()
+ || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) {
+ mLastLetterTypingTime = eventTime;
+ }
+ } else {
+ if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) {
+ // This non-letter typing should be treated as a part of fast typing.
+ mLastLetterTypingTime = eventTime;
+ }
+ }
+ mLastTypingTime = eventTime;
+ }
+
+ public void onEndBatchInput(final long eventTime) {
+ mLastBatchInputTime = eventTime;
+ }
+
+ public long getLastLetterTypingTime() {
+ return mLastLetterTypingTime;
+ }
+
+ public boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
+ return !wasLastInputTyping()
+ && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration;
+ }
+ }
// The position and time at which first down event occurred.
private long mDownTime;
@@ -193,34 +311,32 @@ public class PointerTracker implements PointerTrackerQueue.Element {
// true if this pointer has been long-pressed and is showing a more keys panel.
private boolean mIsShowingMoreKeysPanel;
- // true if this pointer is in sliding key input
+ // true if this pointer is in a sliding key input.
boolean mIsInSlidingKeyInput;
+ // true if this pointer is in a sliding key input from a modifier key,
+ // so that further modifier keys should be ignored.
+ boolean mIsInSlidingKeyInputFromModifier;
- // true if sliding key is allowed.
+ // true if a sliding key input is allowed.
private boolean mIsAllowedSlidingKeyInput;
- // ignore modifier key if true
- private boolean mIgnoreModifierKey;
-
// Empty {@link KeyboardActionListener}
private static final KeyboardActionListener EMPTY_LISTENER =
new KeyboardActionListener.Adapter();
private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints;
- public static void init(boolean hasDistinctMultitouch,
- boolean needsPhantomSuddenMoveEventHack) {
- if (hasDistinctMultitouch) {
- sPointerTrackerQueue = new PointerTrackerQueue();
- } else {
- sPointerTrackerQueue = null;
- }
+ public static void init(final boolean needsPhantomSuddenMoveEventHack) {
sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
sParams = PointerTrackerParams.DEFAULT;
+ sGestureStrokeParams = GestureStrokeParams.DEFAULT;
+ sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
}
public static void setParameters(final TypedArray mainKeyboardViewAttr) {
sParams = new PointerTrackerParams(mainKeyboardViewAttr);
+ sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr);
+ sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
}
private static void updateGestureHandlingMode() {
@@ -254,7 +370,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
public static boolean isAnyInSlidingKeyInput() {
- return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false;
+ return sPointerTrackerQueue.isAnyInSlidingKeyInput();
}
public static void setKeyboardActionListener(final KeyboardActionListener listener) {
@@ -291,7 +407,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
throw new NullPointerException();
}
mPointerId = id;
- mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(id);
+ mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(
+ id, sGestureStrokeParams);
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
@@ -303,11 +420,12 @@ public class PointerTracker implements PointerTrackerQueue.Element {
if (sInGesture) {
return false;
}
- final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
+ final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier();
if (DEBUG_LISTENER) {
- Log.d(TAG, "onPress : " + KeyDetector.printableCode(key)
- + " ignoreModifier=" + ignoreModifierKey
- + " enabled=" + key.isEnabled());
+ Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId,
+ KeyDetector.printableCode(key),
+ ignoreModifierKey ? " ignoreModifier" : "",
+ key.isEnabled() ? "" : " disabled"));
}
if (ignoreModifierKey) {
return false;
@@ -325,15 +443,16 @@ public class PointerTracker implements PointerTrackerQueue.Element {
// Note that we need primaryCode argument because the keyboard may in shifted state and the
// primaryCode is different from {@link Key#mCode}.
private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x,
- final int y) {
- final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
+ final int y, final long eventTime) {
+ final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier();
final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
final int code = altersCode ? key.getAltCode() : primaryCode;
if (DEBUG_LISTENER) {
- Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code)
- + " text=" + key.getOutputText() + " x=" + x + " y=" + y
- + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode
- + " enabled=" + key.isEnabled());
+ final String output = code == Constants.CODE_OUTPUT_TEXT
+ ? key.getOutputText() : Constants.printableCode(code);
+ Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y,
+ output, ignoreModifierKey ? " ignoreModifier" : "",
+ altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled"));
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey,
@@ -344,26 +463,28 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
// Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
if (key.isEnabled() || altersCode) {
- if (code == Keyboard.CODE_OUTPUT_TEXT) {
+ sTimeRecorder.onCodeInput(code, eventTime);
+ if (code == Constants.CODE_OUTPUT_TEXT) {
mListener.onTextInput(key.getOutputText());
- } else if (code != Keyboard.CODE_UNSPECIFIED) {
+ } else if (code != Constants.CODE_UNSPECIFIED) {
mListener.onCodeInput(code, x, y);
}
}
}
- // Note that we need primaryCode argument because the keyboard may in shifted state and the
+ // Note that we need primaryCode argument because the keyboard may be in shifted state and the
// primaryCode is different from {@link Key#mCode}.
private void callListenerOnRelease(final Key key, final int primaryCode,
final boolean withSliding) {
if (sInGesture) {
return;
}
- final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
+ final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier();
if (DEBUG_LISTENER) {
- Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode)
- + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey
- + " enabled="+ key.isEnabled());
+ Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId,
+ Constants.printableCode(primaryCode),
+ withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "",
+ key.isEnabled() ? "": " disabled"));
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding,
@@ -379,7 +500,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
private void callListenerOnCancelInput() {
if (DEBUG_LISTENER) {
- Log.d(TAG, "onCancelInput");
+ Log.d(TAG, String.format("[%d] onCancelInput", mPointerId));
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_callListenerOnCancelInput();
@@ -388,9 +509,15 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
private void setKeyDetectorInner(final KeyDetector keyDetector) {
+ final Keyboard keyboard = keyDetector.getKeyboard();
+ if (keyDetector == mKeyDetector && keyboard == mKeyboard) {
+ return;
+ }
mKeyDetector = keyDetector;
mKeyboard = keyDetector.getKeyboard();
- mGestureStrokeWithPreviewPoints.setKeyboardGeometry(mKeyboard.mMostCommonKeyWidth);
+ final int keyWidth = mKeyboard.mMostCommonKeyWidth;
+ final int keyHeight = mKeyboard.mMostCommonKeyHeight;
+ mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
@@ -398,8 +525,8 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
// Keep {@link #mCurrentKey} that comes from previous keyboard.
}
- final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4;
- mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth;
+ mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD);
+ mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight);
}
@Override
@@ -451,7 +578,12 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
}
- private void setPressedKeyGraphics(final Key key) {
+ private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
+ if (!sShouldHandleGesture) return false;
+ return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime);
+ }
+
+ private void setPressedKeyGraphics(final Key key, final long eventTime) {
if (key == null) {
return;
}
@@ -463,7 +595,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
return;
}
- if (!key.noKeyPreview() && !sInGesture) {
+ if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) {
mDrawingProxy.showKeyPreview(this);
}
updatePressKeyGraphics(key);
@@ -518,10 +650,16 @@ public 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);
@@ -539,71 +677,69 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
private static int getActivePointerTrackerCount() {
- return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size();
+ return sPointerTrackerQueue.size();
+ }
+
+ private static boolean isOldestTrackerInQueue(final PointerTracker tracker) {
+ return sPointerTrackerQueue.getOldestElement() == tracker;
}
- private void mayStartBatchInput() {
+ private void mayStartBatchInput(final Key key) {
if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) {
return;
}
+ if (key == null || !Character.isLetter(key.mCode)) {
+ return;
+ }
if (DEBUG_LISTENER) {
- Log.d(TAG, "onStartBatchInput");
+ Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId));
}
sInGesture = true;
- mListener.onStartBatchInput();
- final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
- mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
+ synchronized (sAggregratedPointers) {
+ sAggregratedPointers.reset();
+ sLastRecognitionPointSize = 0;
+ sLastRecognitionTime = 0;
+ mListener.onStartBatchInput();
+ }
+ mTimerProxy.cancelLongPressTimer();
+ mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
}
- private void updateBatchInput(final long eventTime) {
- synchronized (sAggregratedPointers) {
- mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers);
- final int size = sAggregratedPointers.getPointerSize();
- if (size > sLastRecognitionPointSize
- && GestureStroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
- sLastRecognitionPointSize = size;
- sLastRecognitionTime = eventTime;
- if (DEBUG_LISTENER) {
- Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size);
+ private void mayUpdateBatchInput(final long eventTime, final Key key) {
+ if (key != null) {
+ synchronized (sAggregratedPointers) {
+ final GestureStroke stroke = mGestureStrokeWithPreviewPoints;
+ stroke.appendIncrementalBatchPoints(sAggregratedPointers);
+ final int size = sAggregratedPointers.getPointerSize();
+ if (size > sLastRecognitionPointSize
+ && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) {
+ sLastRecognitionPointSize = size;
+ sLastRecognitionTime = eventTime;
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d",
+ mPointerId, size));
+ }
+ mListener.onUpdateBatchInput(sAggregratedPointers);
}
- mListener.onUpdateBatchInput(sAggregratedPointers);
}
}
- final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
- mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
+ mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
}
- private void mayEndBatchInput() {
+ private void mayEndBatchInput(final long eventTime) {
synchronized (sAggregratedPointers) {
mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers);
- mGestureStrokeWithPreviewPoints.reset();
if (getActivePointerTrackerCount() == 1) {
if (DEBUG_LISTENER) {
- Log.d(TAG, "onEndBatchInput: batchPoints="
- + sAggregratedPointers.getPointerSize());
+ Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d",
+ mPointerId, sAggregratedPointers.getPointerSize()));
}
sInGesture = false;
+ sTimeRecorder.onEndBatchInput(eventTime);
mListener.onEndBatchInput(sAggregratedPointers);
- clearBatchInputPointsOfAllPointerTrackers();
}
}
- final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
- mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
- }
-
- private static void abortBatchInput() {
- clearBatchInputPointsOfAllPointerTrackers();
- }
-
- private static void clearBatchInputPointsOfAllPointerTrackers() {
- final int trackersSize = sTrackers.size();
- for (int i = 0; i < trackersSize; ++i) {
- final PointerTracker tracker = sTrackers.get(i);
- tracker.mGestureStrokeWithPreviewPoints.reset();
- }
- sAggregratedPointers.reset();
- sLastRecognitionPointSize = 0;
- sLastRecognitionTime = 0;
+ mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
}
public void processMotionEvent(final int action, final int x, final int y, final long eventTime,
@@ -639,15 +775,14 @@ public 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;
@@ -655,42 +790,29 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
final Key key = getKeyOn(x, y);
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- if (key != null && key.isModifier()) {
- // Before processing a down event of modifier key, all pointers already being
- // tracked should be released.
- queue.releaseAllPointers(eventTime);
- }
- queue.add(this);
+ mBogusMoveEventDetector.onActualDownEvent(x, y);
+ if (key != null && key.isModifier()) {
+ // Before processing a down event of modifier key, all pointers already being
+ // tracked should be released.
+ sPointerTrackerQueue.releaseAllPointers(eventTime);
}
+ sPointerTrackerQueue.add(this);
onDownEventInternal(x, y, eventTime);
if (!sShouldHandleGesture) {
return;
}
- final int activePointerTrackerCount = getActivePointerTrackerCount();
- if (activePointerTrackerCount == 1) {
- mIsDetectingGesture = false;
- // A gesture should start only from the letter key.
- final boolean isAlphabetKeyboard = (mKeyboard != null)
- && mKeyboard.mId.isAlphabetKeyboard();
- if (isAlphabetKeyboard && !mIsShowingMoreKeysPanel && key != null
- && Keyboard.isLetterCode(key.mCode)) {
+ // A gesture should start only from a non-modifier key.
+ mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
+ && !mIsShowingMoreKeysPanel && key != null && !key.isModifier();
+ if (mIsDetectingGesture) {
+ if (getActivePointerTrackerCount() == 1) {
sGestureFirstDownTime = eventTime;
- onGestureDownEvent(x, y, eventTime);
}
- } else if (sInGesture && activePointerTrackerCount > 1) {
- onGestureDownEvent(x, y, eventTime);
+ mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime,
+ sTimeRecorder.getLastLetterTypingTime());
}
}
- private void onGestureDownEvent(final int x, final int y, final long eventTime) {
- mIsDetectingGesture = true;
- final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime);
- mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown,
- false /* isHistorical */);
- }
-
private void onDownEventInternal(final int x, final int y, final long eventTime) {
Key key = onDownKey(x, y, eventTime);
// Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding
@@ -700,8 +822,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
|| mKeyDetector.alwaysAllowsSlidingInput();
mKeyboardLayoutHasBeenChanged = false;
mKeyAlreadyProcessed = false;
- mIsInSlidingKeyInput = false;
- mIgnoreModifierKey = false;
+ resetSlidingKeyInput();
if (key != null) {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update key according to the new
@@ -712,25 +833,30 @@ public class PointerTracker implements PointerTrackerQueue.Element {
startRepeatKey(key);
startLongPressTimer(key);
- setPressedKeyGraphics(key);
+ setPressedKeyGraphics(key, eventTime);
}
}
private void startSlidingKeyInput(final Key key) {
if (!mIsInSlidingKeyInput) {
- mIgnoreModifierKey = key.isModifier();
+ mIsInSlidingKeyInputFromModifier = key.isModifier();
}
mIsInSlidingKeyInput = true;
}
+ private void resetSlidingKeyInput() {
+ mIsInSlidingKeyInput = false;
+ mIsInSlidingKeyInputFromModifier = false;
+ }
+
private void onGestureMoveEvent(final int x, final int y, final long eventTime,
- final boolean isHistorical, final Key key) {
+ final boolean isMajorEvent, final Key key) {
final int gestureTime = (int)(eventTime - sGestureFirstDownTime);
if (mIsDetectingGesture) {
- mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isHistorical);
- mayStartBatchInput();
- if (sInGesture && key != null) {
- updateBatchInput(eventTime);
+ mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent);
+ mayStartBatchInput(key);
+ if (sInGesture) {
+ mayUpdateBatchInput(eventTime, key);
}
}
}
@@ -752,118 +878,157 @@ public class PointerTracker implements PointerTrackerQueue.Element {
final int historicalY = (int)me.getHistoricalY(pointerIndex, h);
final long historicalTime = me.getHistoricalEventTime(h);
onGestureMoveEvent(historicalX, historicalY, historicalTime,
- true /* isHistorical */, null);
+ false /* isMajorEvent */, null);
}
}
onMoveEventInternal(x, y, eventTime);
}
+ private void processSlidingKeyInput(final Key newKey, final int x, final int y,
+ final long eventTime) {
+ // This onPress call may have changed keyboard layout. Those cases are detected
+ // at {@link #setKeyboard}. In those cases, we should update key according
+ // to the new keyboard layout.
+ Key key = newKey;
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
+ key = onMoveKey(x, y);
+ }
+ onMoveToNewKey(key, x, y);
+ startLongPressTimer(key);
+ setPressedKeyGraphics(key, eventTime);
+ }
+
+ private void processPhantomSuddenMoveHack(final Key key, final int x, final int y,
+ final long eventTime, final Key oldKey, final int lastX, final int lastY) {
+ if (DEBUG_MODE) {
+ 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, Constants.printableCode(oldKey.mCode),
+ x, y, Constants.printableCode(key.mCode)));
+ }
+ // TODO: This should be moved to outside of this nested if-clause?
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
+ }
+ onUpEventInternal(eventTime);
+ onDownEventInternal(x, y, eventTime);
+ }
+
+ private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y,
+ final long eventTime, final Key oldKey, final int lastX, final int lastY) {
+ if (DEBUG_MODE) {
+ final float keyDiagonal = (float)Math.hypot(
+ mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
+ final float radiusRatio =
+ mBogusMoveEventDetector.getDistanceFromDownEvent(x, y)
+ / keyDiagonal;
+ Log.w(TAG, String.format("[%d] onMoveEvent:"
+ + " bogus down-move-up event (raidus=%.2f key diagonal) is "
+ + " translated to up[%d,%d,%s]/down[%d,%d,%s] events",
+ mPointerId, radiusRatio,
+ lastX, lastY, Constants.printableCode(oldKey.mCode),
+ x, y, Constants.printableCode(key.mCode)));
+ }
+ onUpEventInternal(eventTime);
+ onDownEventInternal(x, y, eventTime);
+ }
+
+ private void processSildeOutFromOldKey(final Key oldKey) {
+ setReleasedKeyGraphics(oldKey);
+ callListenerOnRelease(oldKey, oldKey.mCode, true);
+ startSlidingKeyInput(oldKey);
+ mTimerProxy.cancelKeyTimers();
+ }
+
+ private void slideFromOldKeyToNewKey(final Key key, final int x, final int y,
+ final long eventTime, final Key oldKey, final int lastX, final int lastY) {
+ // 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.
+ processSildeOutFromOldKey(oldKey);
+ startRepeatKey(key);
+ if (mIsAllowedSlidingKeyInput) {
+ processSlidingKeyInput(key, x, y, eventTime);
+ }
+ // 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.
+ // TODO: Should find a way to balance gesture detection and this hack.
+ else if (sNeedsPhantomSuddenMoveEventHack
+ && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) {
+ processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY);
+ }
+ // 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)) {
+ processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY);
+ }
+ // HACK: If there are currently multiple touches, register the key even if the finger
+ // slides off the key. This defends against noise from some touch panels when there are
+ // close multiple touches.
+ // Caveat: When in chording input mode with a modifier key, we don't use this hack.
+ else if (getActivePointerTrackerCount() > 1
+ && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) {
+ if (DEBUG_MODE) {
+ Log.w(TAG, String.format("[%d] onMoveEvent:"
+ + " detected sliding finger while multi touching", mPointerId));
+ }
+ onUpEvent(x, y, eventTime);
+ mKeyAlreadyProcessed = true;
+ setReleasedKeyGraphics(oldKey);
+ } else {
+ if (!mIsDetectingGesture) {
+ mKeyAlreadyProcessed = true;
+ }
+ setReleasedKeyGraphics(oldKey);
+ }
+ }
+
+ private void slideOutFromOldKey(final Key oldKey, final int x, final int y) {
+ // The pointer has been slid out from the previous key, we must call onRelease() to
+ // notify that the previous key has been released.
+ processSildeOutFromOldKey(oldKey);
+ if (mIsAllowedSlidingKeyInput) {
+ onMoveToNewKey(null, x, y);
+ } else {
+ if (!mIsDetectingGesture) {
+ mKeyAlreadyProcessed = true;
+ }
+ }
+ }
+
private void onMoveEventInternal(final int x, final int y, final long eventTime) {
final int lastX = mLastX;
final int lastY = mLastY;
final Key oldKey = mCurrentKey;
- Key key = onMoveKey(x, y);
+ final Key newKey = onMoveKey(x, y);
if (sShouldHandleGesture) {
// Register move event on gesture tracker.
- onGestureMoveEvent(x, y, eventTime, false /* isHistorical */, key);
+ onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey);
if (sInGesture) {
- mIgnoreModifierKey = true;
- mTimerProxy.cancelLongPressTimer();
- mIsInSlidingKeyInput = true;
mCurrentKey = null;
setReleasedKeyGraphics(oldKey);
return;
}
}
- if (key != null) {
- if (oldKey == null) {
+ if (newKey != null) {
+ if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) {
+ slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY);
+ } else if (oldKey == null) {
// The pointer has been slid in to the new key, but the finger was not on any keys.
// In this case, we must call onPress() to notify that the new key is being pressed.
- // This onPress call may have changed keyboard layout. Those cases are detected at
- // {@link #setKeyboard}. In those cases, we should update key according to the
- // new keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
- key = onMoveKey(x, y);
- }
- onMoveToNewKey(key, x, y);
- startLongPressTimer(key);
- setPressedKeyGraphics(key);
- } else if (isMajorEnoughMoveToBeOnNewKey(x, y, 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.
- setReleasedKeyGraphics(oldKey);
- callListenerOnRelease(oldKey, oldKey.mCode, true);
- startSlidingKeyInput(oldKey);
- mTimerProxy.cancelKeyTimers();
- startRepeatKey(key);
- if (mIsAllowedSlidingKeyInput) {
- // This onPress call may have changed keyboard layout. Those cases are detected
- // at {@link #setKeyboard}. In those cases, we should update key according
- // to the new keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
- key = onMoveKey(x, y);
- }
- onMoveToNewKey(key, x, y);
- startLongPressTimer(key);
- setPressedKeyGraphics(key);
- } 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
- // 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) {
- 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));
- }
- // TODO: This should be moved to outside of this nested if-clause?
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY);
- }
- onUpEventInternal();
- 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
- // touch panels when there are close multiple touches.
- // Caveat: When in chording input mode with a modifier key, we don't use
- // this hack.
- if (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null
- && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) {
- onUpEventInternal();
- }
- if (!mIsDetectingGesture) {
- mKeyAlreadyProcessed = true;
- }
- setReleasedKeyGraphics(oldKey);
- }
- }
+ processSlidingKeyInput(newKey, x, y, eventTime);
}
- } else {
- if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, 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);
- callListenerOnRelease(oldKey, oldKey.mCode, true);
- startSlidingKeyInput(oldKey);
- mTimerProxy.cancelLongPressTimer();
- if (mIsAllowedSlidingKeyInput) {
- onMoveToNewKey(key, x, y);
- } else {
- if (!mIsDetectingGesture) {
- mKeyAlreadyProcessed = true;
- }
- }
+ } else { // newKey == null
+ if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) {
+ slideOutFromOldKey(oldKey, x, y);
}
}
}
@@ -873,22 +1038,17 @@ public class PointerTracker implements PointerTrackerQueue.Element {
printTouchEvent("onUpEvent :", x, y, eventTime);
}
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- if (!sInGesture) {
- if (mCurrentKey != null && mCurrentKey.isModifier()) {
- // Before processing an up event of modifier key, all pointers already being
- // tracked should be released.
- queue.releaseAllPointersExcept(this, eventTime);
- } else {
- queue.releaseAllPointersOlderThan(this, eventTime);
- }
+ if (!sInGesture) {
+ if (mCurrentKey != null && mCurrentKey.isModifier()) {
+ // Before processing an up event of modifier key, all pointers already being
+ // tracked should be released.
+ sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime);
+ } else {
+ sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime);
}
}
- onUpEventInternal();
- if (queue != null) {
- queue.remove(this);
- }
+ onUpEventInternal(eventTime);
+ sPointerTrackerQueue.remove(this);
}
// Let this pointer tracker know that one of newer-than-this pointer trackers got an up event.
@@ -899,13 +1059,13 @@ public class PointerTracker implements PointerTrackerQueue.Element {
if (DEBUG_EVENT) {
printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime);
}
- onUpEventInternal();
+ onUpEventInternal(eventTime);
mKeyAlreadyProcessed = true;
}
- private void onUpEventInternal() {
+ private void onUpEventInternal(final long eventTime) {
mTimerProxy.cancelKeyTimers();
- mIsInSlidingKeyInput = false;
+ resetSlidingKeyInput();
mIsDetectingGesture = false;
final Key currentKey = mCurrentKey;
mCurrentKey = null;
@@ -920,22 +1080,19 @@ public class PointerTracker implements PointerTrackerQueue.Element {
if (currentKey != null) {
callListenerOnRelease(currentKey, currentKey.mCode, true);
}
- mayEndBatchInput();
+ mayEndBatchInput(eventTime);
return;
}
- // This event will be recognized as a regular code input. Clear unused possible batch points
- // so they are not mistakenly displayed as preview.
- clearBatchInputPointsOfAllPointerTrackers();
+
if (mKeyAlreadyProcessed) {
return;
}
if (currentKey != null && !currentKey.isRepeatable()) {
- detectAndSendKey(currentKey, mKeyX, mKeyY);
+ detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
}
}
public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) {
- abortBatchInput();
onLongPressed();
mIsShowingMoreKeysPanel = true;
onDownEvent(x, y, SystemClock.uptimeMillis(), handler);
@@ -944,10 +1101,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
public void onLongPressed() {
mKeyAlreadyProcessed = true;
setReleasedKeyGraphics(mCurrentKey);
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- queue.remove(this);
- }
+ sPointerTrackerQueue.remove(this);
}
public void onCancelEvent(final int x, final int y, final long eventTime) {
@@ -955,18 +1109,15 @@ public class PointerTracker implements PointerTrackerQueue.Element {
printTouchEvent("onCancelEvt:", x, y, eventTime);
}
- final PointerTrackerQueue queue = sPointerTrackerQueue;
- if (queue != null) {
- queue.releaseAllPointersExcept(this, eventTime);
- queue.remove(this);
- }
+ sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime);
+ sPointerTrackerQueue.remove(this);
onCancelEventInternal();
}
private void onCancelEventInternal() {
mTimerProxy.cancelKeyTimers();
setReleasedKeyGraphics(mCurrentKey);
- mIsInSlidingKeyInput = false;
+ resetSlidingKeyInput();
if (mIsShowingMoreKeysPanel) {
mDrawingProxy.dismissMoreKeysPanel();
mIsShowingMoreKeysPanel = false;
@@ -982,24 +1133,51 @@ public class PointerTracker implements PointerTrackerQueue.Element {
public void onRegisterKey(final Key key) {
if (key != null) {
- detectAndSendKey(key, key.mX, key.mY);
+ detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
mTimerProxy.startTypingStateTimer(key);
}
}
- 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");
}
final Key curKey = mCurrentKey;
if (newKey == curKey) {
return false;
- } else if (curKey != null) {
- return curKey.squaredDistanceToEdge(x, y)
- >= mKeyDetector.getKeyHysteresisDistanceSquared();
- } else {
+ }
+ if (curKey == null /* && newKey != null */) {
+ return true;
+ }
+ // Here curKey points to the different key from newKey.
+ final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared(
+ mIsInSlidingKeyInputFromModifier);
+ final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y);
+ if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) {
+ if (DEBUG_MODE) {
+ final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared)
+ / mKeyboard.mMostCommonKeyWidth;
+ Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
+ +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio));
+ }
return true;
}
+ if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput
+ && sTimeRecorder.isInFastTyping(eventTime)
+ && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) {
+ if (DEBUG_MODE) {
+ final float keyDiagonal = (float)Math.hypot(
+ mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
+ final float lengthFromDownRatio =
+ mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal;
+ Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
+ + " %.2f key diagonal from virtual down point",
+ mPointerId, lengthFromDownRatio));
+ }
+ return true;
+ }
+ return false;
}
private void startLongPressTimer(final Key key) {
@@ -1008,14 +1186,14 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
}
- private void detectAndSendKey(final Key key, final int x, final int y) {
+ private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) {
if (key == null) {
callListenerOnCancelInput();
return;
}
final int code = key.mCode;
- callListenerOnCodeInput(key, code, x, y);
+ callListenerOnCodeInput(key, code, x, y, eventTime);
callListenerOnRelease(key, code, false);
}
@@ -1023,7 +1201,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
final long eventTime) {
final Key key = mKeyDetector.detectHitKey(x, y);
final String code = KeyDetector.printableCode(key);
- Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title,
- (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, eventTime, code));
+ Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId,
+ (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code));
}
}