aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod
diff options
context:
space:
mode:
authorTadashi G. Takaoka <takaoka@google.com>2012-09-28 06:54:04 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2012-09-28 06:54:04 -0700
commit99501896f51a051c09ec345177d78554cdd60fd1 (patch)
treec4896c912779619b96d62dd471271bfd2ea67595 /java/src/com/android/inputmethod
parent11dbf025c63197246bf717e87122ab38ff05faf7 (diff)
parent9925e487b345e4a63d3dc25e3bf156e0fbfbb04d (diff)
downloadlatinime-99501896f51a051c09ec345177d78554cdd60fd1.tar.gz
latinime-99501896f51a051c09ec345177d78554cdd60fd1.tar.xz
latinime-99501896f51a051c09ec345177d78554cdd60fd1.zip
am 9925e487: am 6052a81e: Merge "Fix gesture detection algorithm" into jb-mr1-dev
* commit '9925e487b345e4a63d3dc25e3bf156e0fbfbb04d': Fix gesture detection algorithm
Diffstat (limited to 'java/src/com/android/inputmethod')
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java86
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java166
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java47
4 files changed, 172 insertions, 129 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 7e2a5af90..ad7d0a39f 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -172,8 +172,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private static long sLastLetterTypingUpTime;
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
// The position and time at which first down event occurred.
private long mDownTime;
@@ -310,9 +310,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
final boolean ignoreModifierKey = mIgnoreModifierKey && 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;
@@ -335,10 +336,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
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 == Keyboard.CODE_OUTPUT_TEXT
+ ? key.getOutputText() : Keyboard.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,
@@ -367,9 +369,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
final boolean ignoreModifierKey = mIgnoreModifierKey && 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,
+ Keyboard.printableCode(primaryCode),
+ withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "",
+ key.isEnabled() ? "": " disabled"));
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding,
@@ -385,7 +388,7 @@ public final 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();
@@ -394,6 +397,10 @@ public final 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);
@@ -564,10 +571,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return;
}
if (DEBUG_LISTENER) {
- Log.d(TAG, "onStartBatchInput");
+ Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId));
}
sInGesture = true;
- mListener.onStartBatchInput();
+ synchronized (sAggregratedPointers) {
+ sAggregratedPointers.reset();
+ sLastRecognitionPointSize = 0;
+ sLastRecognitionTime = 0;
+ mListener.onStartBatchInput();
+ }
final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this;
mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
}
@@ -582,7 +594,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
sLastRecognitionPointSize = size;
sLastRecognitionTime = eventTime;
if (DEBUG_LISTENER) {
- Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size);
+ Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d",
+ mPointerId, size));
}
mListener.onUpdateBatchInput(sAggregratedPointers);
}
@@ -595,37 +608,20 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
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;
sLastBatchInputTime = 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;
- }
-
public void processMotionEvent(final int action, final int x, final int y, final long eventTime,
final KeyEventHandler handler) {
switch (action) {
@@ -695,18 +691,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (getActivePointerTrackerCount() == 1) {
sGestureFirstDownTime = eventTime;
}
- onGestureDownEvent(x, y, eventTime);
+ mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime,
+ sLastLetterTypingUpTime);
}
}
- private void onGestureDownEvent(final int x, final int y, final long eventTime) {
- mIsDetectingGesture = true;
- mGestureStrokeWithPreviewPoints.setLastLetterTypingTime(eventTime, sLastLetterTypingUpTime);
- final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime);
- mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown,
- true /* isMajorEvent */);
- }
-
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
@@ -939,9 +928,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
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;
}
@@ -955,7 +942,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) {
- abortBatchInput();
onLongPressed();
mIsShowingMoreKeysPanel = true;
onDownEvent(x, y, SystemClock.uptimeMillis(), handler);
@@ -1043,7 +1029,7 @@ public final 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));
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index 9fe6fa3f8..c0e92df32 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -22,6 +22,7 @@ import com.android.inputmethod.latin.ResizableIntArray;
public class GestureStroke {
private static final String TAG = GestureStroke.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_SPEED = false;
public static final int DEFAULT_CAPACITY = 128;
@@ -29,42 +30,52 @@ public class GestureStroke {
private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY);
private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
- private int mIncrementalRecognitionSize;
- private int mLastIncrementalBatchSize;
- private long mLastMajorEventTime;
- private int mLastMajorEventX;
- private int mLastMajorEventY;
- private boolean mAfterFastTyping;
- private int mKeyWidth;
- private int mStartGestureLengthThresholdAfterFastTyping; // pixel
- private int mStartGestureLengthThreshold; // pixel
- private int mMinGestureSamplingLength; // pixel
- private int mGestureRecognitionSpeedThreshold; // pixel / sec
+ private int mKeyWidth; // pixel
+ // Static threshold for starting gesture detection
private int mDetectFastMoveSpeedThreshold; // pixel /sec
private int mDetectFastMoveTime;
private int mDetectFastMoveX;
private int mDetectFastMoveY;
+ // Dynamic threshold for gesture after fast typing
+ private boolean mAfterFastTyping;
+ private int mGestureDynamicDistanceThresholdFrom; // pixel
+ private int mGestureDynamicDistanceThresholdTo; // pixel
+ // Variables for gesture sampling
+ private int mGestureSamplingMinimumDistance; // pixel
+ private long mLastMajorEventTime;
+ private int mLastMajorEventX;
+ private int mLastMajorEventY;
+ // Variables for gesture recognition
+ private int mGestureRecognitionSpeedThreshold; // pixel / sec
+ private int mIncrementalRecognitionSize;
+ private int mLastIncrementalBatchSize;
// TODO: Move some of these to resource.
- private static final int GESTURE_AFTER_FAST_TYPING_DURATION_THRESHOLD = 350; // msec
- private static final float START_GESTURE_LENGTH_THRESHOLD_AFTER_FAST_TYPING_RATIO_TO_KEY_WIDTH =
- 8.0f;
- private static final int START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION = 400; // msec
- private static final float START_GESTURE_LENGTH_THRESHOLD_RATIO_TO_KEY_WIDTH = 0.6f;
- private static final int START_GESTURE_DURATION_THRESHOLD = 70; // msec
- private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec
- private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f;
- private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH =
- 5.5f; // keyWidth / sec
- private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH =
- 5.0f; // keyWidth / sec
- private static final int MSEC_PER_SEC = 1000;
- public static final boolean hasRecognitionTimePast(
- final long currentTime, final long lastRecognitionTime) {
- return currentTime > lastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME;
- }
+ // Static threshold for gesture after fast typing
+ public static final int GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING = 350; // msec
+
+ // Static threshold for starting gesture detection
+ private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD = 1.5f; // keyWidth / sec
+
+ // Dynamic threshold for gesture after fast typing
+ private static final int GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION = 450; // msec
+ // Time based threshold values
+ private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_FROM = 300; // msec
+ private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_TO = 20; // msec
+ // Distance based threshold values
+ private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM = 6.0f; // keyWidth
+ private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO = 0.35f; // keyWidth
+
+ // Parameters for gesture sampling
+ private static final float GESTURE_SAMPLING_MINIMUM_DISTANCE = 1.0f / 6.0f; // keyWidth
+
+ // Parameters for gesture recognition
+ private static final int GESTURE_RECOGNITION_MINIMUM_TIME = 100; // msec
+ private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD = 5.5f; // keyWidth / sec
+
+ private static final int MSEC_PER_SEC = 1000;
public GestureStroke(final int pointerId) {
mPointerId = pointerId;
@@ -73,41 +84,58 @@ public class GestureStroke {
public void setKeyboardGeometry(final int keyWidth) {
mKeyWidth = keyWidth;
// TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
- mStartGestureLengthThresholdAfterFastTyping = (int)(keyWidth
- * START_GESTURE_LENGTH_THRESHOLD_AFTER_FAST_TYPING_RATIO_TO_KEY_WIDTH);
- mStartGestureLengthThreshold =
- (int)(keyWidth * START_GESTURE_LENGTH_THRESHOLD_RATIO_TO_KEY_WIDTH);
- mMinGestureSamplingLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH);
+ mDetectFastMoveSpeedThreshold = (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD);
+ mGestureDynamicDistanceThresholdFrom =
+ (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM);
+ mGestureDynamicDistanceThresholdTo =
+ (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO);
+ mGestureSamplingMinimumDistance = (int)(keyWidth * GESTURE_SAMPLING_MINIMUM_DISTANCE);
mGestureRecognitionSpeedThreshold =
- (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH);
- mDetectFastMoveSpeedThreshold =
- (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH);
+ (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD);
if (DEBUG) {
- Log.d(TAG, "[" + mPointerId + "] setKeyboardGeometry: keyWidth=" + keyWidth
- + " tL0=" + mStartGestureLengthThresholdAfterFastTyping
- + " tL=" + mStartGestureLengthThreshold);
+ Log.d(TAG, String.format(
+ "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d",
+ mPointerId, keyWidth,
+ GESTURE_DYNAMIC_TIME_THRESHOLD_FROM,
+ GESTURE_DYNAMIC_TIME_THRESHOLD_TO,
+ mGestureDynamicDistanceThresholdFrom,
+ mGestureDynamicDistanceThresholdTo));
}
}
- public void setLastLetterTypingTime(final long downTime, final long lastTypingTime) {
- final long elpasedTimeAfterTyping = downTime - lastTypingTime;
- if (elpasedTimeAfterTyping < GESTURE_AFTER_FAST_TYPING_DURATION_THRESHOLD) {
+ public void onDownEvent(final int x, final int y, final long downTime,
+ final long gestureFirstDownTime, final long lastTypingTime) {
+ reset();
+ final long elapsedTimeAfterTyping = downTime - lastTypingTime;
+ if (elapsedTimeAfterTyping < GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING) {
mAfterFastTyping = true;
}
if (DEBUG) {
- Log.d(TAG, "[" + mPointerId + "] setLastTypingTime: dT=" + elpasedTimeAfterTyping
- + " afterFastTyping=" + mAfterFastTyping);
+ Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId,
+ elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : ""));
}
+ final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime);
+ addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */);
}
- private int getStartGestureLengthThreshold(final int deltaTime) {
- if (!mAfterFastTyping || deltaTime >= START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION) {
- return mStartGestureLengthThreshold;
+ private int getGestureDynamicDistanceThreshold(final int deltaTime) {
+ if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) {
+ return mGestureDynamicDistanceThresholdTo;
}
final int decayedThreshold =
- (mStartGestureLengthThresholdAfterFastTyping - mStartGestureLengthThreshold)
- * deltaTime / START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION;
- return mStartGestureLengthThresholdAfterFastTyping - decayedThreshold;
+ (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo)
+ * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION;
+ return mGestureDynamicDistanceThresholdFrom - decayedThreshold;
+ }
+
+ private int getGestureDynamicTimeThreshold(final int deltaTime) {
+ if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) {
+ return GESTURE_DYNAMIC_TIME_THRESHOLD_TO;
+ }
+ final int decayedThreshold =
+ (GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - GESTURE_DYNAMIC_TIME_THRESHOLD_TO)
+ * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION;
+ return GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - decayedThreshold;
}
public boolean isStartOfAGesture() {
@@ -120,21 +148,24 @@ public class GestureStroke {
}
final int lastIndex = size - 1;
final int deltaTime = mEventTimes.get(lastIndex) - mDetectFastMoveTime;
- final int deltaLength = getDistance(
+ final int deltaDistance = getDistance(
mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex),
mDetectFastMoveX, mDetectFastMoveY);
- final int startGestureLengthThreshold = getStartGestureLengthThreshold(deltaTime);
- final boolean isStartOfAGesture = deltaTime > START_GESTURE_DURATION_THRESHOLD
- && deltaLength > startGestureLengthThreshold;
+ final int distanceThreshold = getGestureDynamicDistanceThreshold(deltaTime);
+ final int timeThreshold = getGestureDynamicTimeThreshold(deltaTime);
+ final boolean isStartOfAGesture = deltaTime >= timeThreshold
+ && deltaDistance >= distanceThreshold;
if (DEBUG) {
- Log.d(TAG, "[" + mPointerId + "] isStartOfAGesture: dT=" + deltaTime
- + " dL=" + deltaLength + " tL=" + startGestureLengthThreshold
- + " points=" + size + (isStartOfAGesture ? " Detect start of a gesture" : ""));
+ Log.d(TAG, String.format("[%d] isStartOfAGesture: dT=%3d tT=%3d dD=%3d tD=%3d%s%s",
+ mPointerId, deltaTime, timeThreshold,
+ deltaDistance, distanceThreshold,
+ mAfterFastTyping ? " afterFastTyping" : "",
+ isStartOfAGesture ? " startOfAGesture" : ""));
}
return isStartOfAGesture;
}
- public void reset() {
+ protected void reset() {
mIncrementalRecognitionSize = 0;
mLastIncrementalBatchSize = 0;
mEventTimes.setLength(0);
@@ -167,15 +198,17 @@ public class GestureStroke {
if (msecs > 0) {
final int pixels = getDistance(lastX, lastY, x, y);
final int pixelsPerSec = pixels * MSEC_PER_SEC;
- if (DEBUG) {
+ if (DEBUG_SPEED) {
final float speed = (float)pixelsPerSec / msecs / mKeyWidth;
- Log.d(TAG, String.format("[" + mPointerId + "] speed=%.3f", speed));
+ Log.d(TAG, String.format("[%d] detectFastMove: speed=%5.2f", mPointerId, speed));
}
// Equivalent to (pixels / msecs < mStartSpeedThreshold / MSEC_PER_SEC)
if (mDetectFastMoveTime == 0 && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) {
if (DEBUG) {
- Log.d(TAG, "[" + mPointerId + "] detect fast move: T="
- + time + " points = " + size);
+ final float speed = (float)pixelsPerSec / msecs / mKeyWidth;
+ Log.d(TAG, String.format(
+ "[%d] detectFastMove: speed=%5.2f T=%3d points=%3d fastMove",
+ mPointerId, speed, time, size));
}
mDetectFastMoveTime = time;
mDetectFastMoveX = x;
@@ -192,8 +225,8 @@ public class GestureStroke {
appendPoint(x, y, time);
updateMajorEvent(x, y, time);
} else {
- final int dist = detectFastMove(x, y, time);
- if (dist > mMinGestureSamplingLength) {
+ final int distance = detectFastMove(x, y, time);
+ if (distance > mGestureSamplingMinimumDistance) {
appendPoint(x, y, time);
}
}
@@ -216,6 +249,11 @@ public class GestureStroke {
}
}
+ public static final boolean hasRecognitionTimePast(
+ final long currentTime, final long lastRecognitionTime) {
+ return currentTime > lastRecognitionTime + GESTURE_RECOGNITION_MINIMUM_TIME;
+ }
+
public void appendAllBatchPoints(final InputPointers out) {
appendBatchPoints(out, mEventTimes.getLength());
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
index 5b3f31805..05e0a2ec3 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
@@ -38,7 +38,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
}
@Override
- public void reset() {
+ protected void reset() {
super.reset();
mStrokeId++;
mLastPreviewSize = 0;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 3e893303f..268d36ad2 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1402,6 +1402,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@Override
public void onStartBatchInput() {
+ BatchInputUpdater.getInstance().onStartBatchInput();
mConnection.beginBatchEdit();
if (mWordComposer.isComposingWord()) {
if (ProductionFlag.IS_INTERNAL) {
@@ -1433,6 +1434,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private static final class BatchInputUpdater implements Handler.Callback {
private final Handler mHandler;
private LatinIME mLatinIme;
+ private boolean mInBatchInput; // synchornized using "this".
private BatchInputUpdater() {
final HandlerThread handlerThread = new HandlerThread(
@@ -1456,17 +1458,32 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
public boolean handleMessage(final Message msg) {
switch (msg.what) {
case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
- final SuggestedWords suggestedWords = getSuggestedWordsGesture(
- (InputPointers)msg.obj, mLatinIme);
- showGesturePreviewAndSuggestionStrip(
- suggestedWords, false /* dismissGestureFloatingPreviewText */, mLatinIme);
+ updateBatchInput((InputPointers)msg.obj, mLatinIme);
break;
}
return true;
}
- public void updateGesturePreviewAndSuggestionStrip(final InputPointers batchPointers,
+ // Run in the UI thread.
+ public synchronized void onStartBatchInput() {
+ mInBatchInput = true;
+ }
+
+ // Run in the Handler thread.
+ private synchronized void updateBatchInput(final InputPointers batchPointers,
final LatinIME latinIme) {
+ if (!mInBatchInput) {
+ // Batch input has ended while the message was being delivered.
+ return;
+ }
+ final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(
+ batchPointers, latinIme);
+ latinIme.mHandler.showGesturePreviewAndSuggestionStrip(
+ suggestedWords, false /* dismissGestureFloatingPreviewText */);
+ }
+
+ // Run in the UI thread.
+ public void onUpdateBatchInput(final InputPointers batchPointers, final LatinIME latinIme) {
mLatinIme = latinIme;
if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) {
return;
@@ -1476,15 +1493,20 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
.sendToTarget();
}
- public void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords,
- final boolean dismissGestureFloatingPreviewText, final LatinIME latinIme) {
+ // Run in the UI thread.
+ public synchronized SuggestedWords onEndBatchInput(final InputPointers batchPointers,
+ final LatinIME latinIme) {
+ mInBatchInput = false;
+ final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(
+ batchPointers, latinIme);
latinIme.mHandler.showGesturePreviewAndSuggestionStrip(
- suggestedWords, dismissGestureFloatingPreviewText);
+ suggestedWords, true /* dismissGestureFloatingPreviewText */);
+ return suggestedWords;
}
// {@link LatinIME#getSuggestedWords(int)} method calls with same session id have to
// be synchronized.
- public synchronized SuggestedWords getSuggestedWordsGesture(
+ private static SuggestedWords getSuggestedWordsGestureLocked(
final InputPointers batchPointers, final LatinIME latinIme) {
latinIme.mWordComposer.setBatchInputPointers(batchPointers);
return latinIme.getSuggestedWords(Suggest.SESSION_GESTURE);
@@ -1505,16 +1527,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@Override
public void onUpdateBatchInput(final InputPointers batchPointers) {
- BatchInputUpdater.getInstance().updateGesturePreviewAndSuggestionStrip(batchPointers, this);
+ BatchInputUpdater.getInstance().onUpdateBatchInput(batchPointers, this);
}
@Override
public void onEndBatchInput(final InputPointers batchPointers) {
- final BatchInputUpdater batchInputUpdater = BatchInputUpdater.getInstance();
- final SuggestedWords suggestedWords = batchInputUpdater.getSuggestedWordsGesture(
+ final SuggestedWords suggestedWords = BatchInputUpdater.getInstance().onEndBatchInput(
batchPointers, this);
- batchInputUpdater.showGesturePreviewAndSuggestionStrip(
- suggestedWords, true /* dismissGestureFloatingPreviewText */, this);
final String batchInputText = (suggestedWords.size() > 0)
? suggestedWords.getWord(0) : null;
if (TextUtils.isEmpty(batchInputText)) {