aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java55
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java25
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java6
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java11
-rw-r--r--native/jni/src/defines.h2
-rw-r--r--native/jni/src/proximity_info_state.cpp115
-rw-r--r--native/jni/src/proximity_info_state.h29
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java3
11 files changed, 211 insertions, 59 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index b612f0927..14da9ebe6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -80,6 +80,8 @@ public interface KeyboardActionListener {
*/
public void onEndBatchInput(InputPointers batchPointers);
+ public void onCancelBatchInput();
+
/**
* Called when user released a finger outside any key.
*/
@@ -107,6 +109,8 @@ public interface KeyboardActionListener {
@Override
public void onEndBatchInput(InputPointers batchPointers) {}
@Override
+ public void onCancelBatchInput() {}
+ @Override
public void onCancelInput() {}
@Override
public boolean onCustomRequest(int requestCode) {
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index c86805232..c8052af6a 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -305,8 +305,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// true if keyboard layout has been changed.
private boolean mKeyboardLayoutHasBeenChanged;
- // true if event is already translated to a key action.
- private boolean mKeyAlreadyProcessed;
+ // true if this pointer is no longer tracking touch event.
+ private boolean mIsTrackingCanceled;
// true if this pointer has been long-pressed and is showing a more keys panel.
private boolean mIsShowingMoreKeysPanel;
@@ -517,7 +517,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mKeyboard = keyDetector.getKeyboard();
final int keyWidth = mKeyboard.mMostCommonKeyWidth;
final int keyHeight = mKeyboard.mMostCommonKeyHeight;
- mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth);
+ mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
@@ -730,13 +730,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
synchronized (sAggregratedPointers) {
mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers);
if (getActivePointerTrackerCount() == 1) {
- if (DEBUG_LISTENER) {
- Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d",
- mPointerId, sAggregratedPointers.getPointerSize()));
- }
sInGesture = false;
sTimeRecorder.onEndBatchInput(eventTime);
- mListener.onEndBatchInput(sAggregratedPointers);
+ if (!mIsTrackingCanceled) {
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d",
+ mPointerId, sAggregratedPointers.getPointerSize()));
+ }
+ mListener.onEndBatchInput(sAggregratedPointers);
+ }
}
}
mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this));
@@ -784,7 +786,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance);
}
- mKeyAlreadyProcessed = true;
+ cancelTracking();
return;
}
}
@@ -821,7 +823,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|| (key != null && key.isModifier())
|| mKeyDetector.alwaysAllowsSlidingInput();
mKeyboardLayoutHasBeenChanged = false;
- mKeyAlreadyProcessed = false;
+ mIsTrackingCanceled = false;
resetSlidingKeyInput();
if (key != null) {
// This onPress call may have changed keyboard layout. Those cases are detected at
@@ -853,7 +855,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final boolean isMajorEvent, final Key key) {
final int gestureTime = (int)(eventTime - sGestureFirstDownTime);
if (mIsDetectingGesture) {
- mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent);
+ final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard(
+ x, y, gestureTime, isMajorEvent);
+ if (!onValidArea) {
+ sPointerTrackerQueue.cancelAllPointerTracker();
+ if (DEBUG_LISTENER) {
+ Log.d(TAG, String.format("[%d] onCancelBatchInput: batchPoints=%d",
+ mPointerId, sAggregratedPointers.getPointerSize()));
+ }
+ mListener.onCancelBatchInput();
+ return;
+ }
mayStartBatchInput(key);
if (sInGesture) {
mayUpdateBatchInput(eventTime, key);
@@ -865,7 +877,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (DEBUG_MOVE_EVENT) {
printTouchEvent("onMoveEvent:", x, y, eventTime);
}
- if (mKeyAlreadyProcessed) {
+ if (mIsTrackingCanceled) {
return;
}
@@ -979,11 +991,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
+ " detected sliding finger while multi touching", mPointerId));
}
onUpEvent(x, y, eventTime);
- mKeyAlreadyProcessed = true;
+ cancelTracking();
setReleasedKeyGraphics(oldKey);
} else {
if (!mIsDetectingGesture) {
- mKeyAlreadyProcessed = true;
+ cancelTracking();
}
setReleasedKeyGraphics(oldKey);
}
@@ -997,7 +1009,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
onMoveToNewKey(null, x, y);
} else {
if (!mIsDetectingGesture) {
- mKeyAlreadyProcessed = true;
+ cancelTracking();
}
}
}
@@ -1060,7 +1072,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime);
}
onUpEventInternal(eventTime);
- mKeyAlreadyProcessed = true;
+ cancelTracking();
}
private void onUpEventInternal(final long eventTime) {
@@ -1084,7 +1096,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
return;
}
- if (mKeyAlreadyProcessed) {
+ if (mIsTrackingCanceled) {
return;
}
if (currentKey != null && !currentKey.isRepeatable()) {
@@ -1098,8 +1110,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
onDownEvent(x, y, SystemClock.uptimeMillis(), handler);
}
+ @Override
+ public void cancelTracking() {
+ mIsTrackingCanceled = true;
+ }
+
public void onLongPressed() {
- mKeyAlreadyProcessed = true;
+ cancelTracking();
setReleasedKeyGraphics(mCurrentKey);
sPointerTrackerQueue.remove(this);
}
@@ -1202,6 +1219,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
final Key key = mKeyDetector.detectHitKey(x, y);
final String code = KeyDetector.printableCode(key);
Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId,
- (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code));
+ (mIsTrackingCanceled ? "-" : " "), 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 f8244dd5b..aab14e968 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -27,6 +27,10 @@ public class GestureStroke {
private static final boolean DEBUG = false;
private static final boolean DEBUG_SPEED = false;
+ // The height of extra area above the keyboard to draw gesture trails.
+ // Proportional to the keyboard height.
+ public static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f;
+
public static final int DEFAULT_CAPACITY = 128;
private final int mPointerId;
@@ -37,6 +41,8 @@ public class GestureStroke {
private final GestureStrokeParams mParams;
private int mKeyWidth; // pixel
+ private int mMinYCoordinate; // pixel
+ private int mMaxYCoordinate; // pixel
// Static threshold for starting gesture detection
private int mDetectFastMoveSpeedThreshold; // pixel /sec
private int mDetectFastMoveTime;
@@ -135,8 +141,10 @@ public class GestureStroke {
mParams = params;
}
- public void setKeyboardGeometry(final int keyWidth) {
+ public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) {
mKeyWidth = keyWidth;
+ mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
+ mMaxYCoordinate = keyboardHeight - 1;
// TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold);
mGestureDynamicDistanceThresholdFrom =
@@ -167,7 +175,7 @@ public class GestureStroke {
elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : ""));
}
final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime);
- addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */);
+ addPointOnKeyboard(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */);
}
private int getGestureDynamicDistanceThreshold(final int deltaTime) {
@@ -277,7 +285,17 @@ public class GestureStroke {
return dist;
}
- public void addPoint(final int x, final int y, final int time, final boolean isMajorEvent) {
+ /**
+ * Add a touch event as a gesture point. Returns true if the touch event is on the valid
+ * gesture area.
+ * @param x the x-coordinate of the touch event
+ * @param y the y-coordinate of the touch event
+ * @param time the elapsed time in millisecond from the first gesture down
+ * @param isMajorEvent false if this is a historical move event
+ * @return true if the touch event is on the valid gesture area
+ */
+ public boolean addPointOnKeyboard(final int x, final int y, final int time,
+ final boolean isMajorEvent) {
final int size = mEventTimes.getLength();
if (size <= 0) {
// Down event
@@ -293,6 +311,7 @@ public class GestureStroke {
updateIncrementalRecognitionSize(x, y, time);
updateMajorEvent(x, y, time);
}
+ return y >= mMinYCoordinate && y < mMaxYCoordinate;
}
private void updateIncrementalRecognitionSize(final int x, final int y, final int time) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
index 8192c9076..7ab7e9aad 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
@@ -56,8 +56,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
}
@Override
- public void setKeyboardGeometry(final int keyWidth) {
- super.setKeyboardGeometry(keyWidth);
+ public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) {
+ super.setKeyboardGeometry(keyWidth, keyboardHeight);
final float sampleLength = keyWidth * MIN_PREVIEW_SAMPLE_LENGTH_RATIO_TO_KEY_WIDTH;
mMinPreviewSampleLengthSquare = (int)(sampleLength * sampleLength);
}
@@ -69,8 +69,9 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
}
@Override
- public void addPoint(final int x, final int y, final int time, final boolean isMajorEvent) {
- super.addPoint(x, y, time, isMajorEvent);
+ public boolean addPointOnKeyboard(final int x, final int y, final int time,
+ final boolean isMajorEvent) {
+ final boolean onValidArea = super.addPointOnKeyboard(x, y, time, isMajorEvent);
if (isMajorEvent || needsSampling(x, y)) {
mPreviewEventTimes.add(time);
mPreviewXCoordinates.add(x);
@@ -78,6 +79,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
mLastX = x;
mLastY = y;
}
+ return onValidArea;
}
public void appendPreviewStroke(final ResizableIntArray eventTimes,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
index a52f202aa..00fc885e8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
@@ -30,6 +30,7 @@ public final class PointerTrackerQueue {
public boolean isModifier();
public boolean isInSlidingKeyInput();
public void onPhantomUpEvent(long eventTime);
+ public void cancelTracking();
}
private static final int INITIAL_CAPACITY = 10;
@@ -182,6 +183,15 @@ public final class PointerTrackerQueue {
return false;
}
+ public synchronized void cancelAllPointerTracker() {
+ final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+ final int arraySize = mArraySize;
+ for (int index = 0; index < arraySize; index++) {
+ final Element element = expandableArray.get(index);
+ element.cancelTracking();
+ }
+ }
+
@Override
public synchronized String toString() {
final StringBuilder sb = new StringBuilder();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index 776ac0204..0d44ecdff 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -40,10 +40,6 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
public final class PreviewPlacerView extends RelativeLayout {
- // The height of extra area above the keyboard to draw gesture trails.
- // Proportional to the keyboard height.
- private static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f;
-
private final int mGestureFloatingPreviewTextColor;
private final int mGestureFloatingPreviewTextOffset;
private final int mGestureFloatingPreviewColor;
@@ -175,7 +171,7 @@ public final class PreviewPlacerView extends RelativeLayout {
public void setKeyboardViewGeometry(final int x, final int y, final int w, final int h) {
mKeyboardViewOriginX = x;
mKeyboardViewOriginY = y;
- mOffscreenOffsetY = (int)(h * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
+ mOffscreenOffsetY = (int)(h * GestureStroke.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
mOffscreenWidth = w;
mOffscreenHeight = mOffscreenOffsetY + h;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e3508ac44..dc3ad4ff0 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1528,6 +1528,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
.sendToTarget();
}
+ public void onCancelBatchInput(final LatinIME latinIme) {
+ mInBatchInput = false;
+ latinIme.mHandler.showGesturePreviewAndSuggestionStrip(
+ SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */);
+ }
+
// Run in the UI thread.
public synchronized SuggestedWords onEndBatchInput(final InputPointers batchPointers,
final LatinIME latinIme) {
@@ -1613,6 +1619,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mKeyboardSwitcher.onCancelInput();
}
+ @Override
+ public void onCancelBatchInput() {
+ BatchInputUpdater.getInstance().onCancelBatchInput(this);
+ }
+
private void handleBackspace(final int spaceState) {
// In many cases, we may have to put the keyboard in auto-shift state again. However
// we want to wait a few milliseconds before doing it to avoid the keyboard flashing
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index bbef7329d..894e5f1c9 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -210,6 +210,7 @@ static inline void prof_out(void) {
#define DEBUG_WORDS_PRIORITY_QUEUE false
#define DEBUG_SAMPLING_POINTS true
#define DEBUG_POINTS_PROBABILITY true
+#define DEBUG_DOUBLE_LETTER true
#ifdef FLAG_FULL_DBG
#define DEBUG_GEO_FULL true
@@ -232,6 +233,7 @@ static inline void prof_out(void) {
#define DEBUG_WORDS_PRIORITY_QUEUE false
#define DEBUG_SAMPLING_POINTS false
#define DEBUG_POINTS_PROBABILITY false
+#define DEBUG_DOUBLE_LETTER false
#define DEBUG_GEO_FULL false
diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index e64d46d01..740e1a24e 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -21,7 +21,6 @@
#define LOG_TAG "LatinIME: proximity_info_state.cpp"
#include "defines.h"
-#include "geometry_utils.h"
#include "proximity_info.h"
#include "proximity_info_state.h"
@@ -37,7 +36,6 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize,
const int *const xCoordinates, const int *const yCoordinates, const int *const times,
const int *const pointerIds, const bool isGeometric) {
-
if (isGeometric) {
mIsContinuationPossible = checkAndReturnIsContinuationPossible(
inputSize, xCoordinates, yCoordinates, times);
@@ -106,7 +104,8 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
mDistanceCache.clear();
mNearKeysVector.clear();
mSearchKeysVector.clear();
- mRelativeSpeeds.clear();
+ mSpeedRates.clear();
+ mBeelineSpeedRates.clear();
mCharProbabilities.clear();
mDirections.clear();
}
@@ -117,6 +116,14 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
mSampledInputSize = 0;
if (xCoordinates && yCoordinates) {
+ if (DEBUG_SAMPLING_POINTS) {
+ if (isGeometric) {
+ for (int i = 0; i < inputSize; ++i) {
+ AKLOGI("(%d) x %d, y %d, time %d",
+ i, xCoordinates[i], yCoordinates[i], times[i]);
+ }
+ }
+ }
const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0);
int lastInputIndex = pushTouchPointStartIndex;
for (int i = lastInputIndex; i < inputSize; ++i) {
@@ -179,7 +186,8 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
}
if (mSampledInputSize > 0 && isGeometric) {
- refreshRelativeSpeed(inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize);
+ refreshSpeedRates(inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize);
+ refreshBeelineSpeedRates(inputSize, xCoordinates, yCoordinates, times);
}
if (DEBUG_GEO_FULL) {
@@ -242,7 +250,13 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
originalY << ";";
}
}
+ AKLOGI("===== sampled points =====");
for (int i = 0; i < mSampledInputSize; ++i) {
+ if (isGeometric) {
+ AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %.4f",
+ i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i],
+ getBeelineSpeedRate(i));
+ }
sampledX << mSampledInputXs[i];
sampledY << mSampledInputYs[i];
if (i != mSampledInputSize - 1) {
@@ -303,13 +317,13 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
}
}
-void ProximityInfoState::refreshRelativeSpeed(const int inputSize, const int *const xCoordinates,
+void ProximityInfoState::refreshSpeedRates(const int inputSize, const int *const xCoordinates,
const int *const yCoordinates, const int *const times, const int lastSavedInputSize) {
// Relative speed calculation.
const int sumDuration = mTimes.back() - mTimes.front();
const int sumLength = mLengthCache.back() - mLengthCache.front();
- const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration);
- mRelativeSpeeds.resize(mSampledInputSize);
+ mAverageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration);
+ mSpeedRates.resize(mSampledInputSize);
for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) {
const int index = mInputIndice[i];
int length = 0;
@@ -331,16 +345,17 @@ void ProximityInfoState::refreshRelativeSpeed(const int inputSize, const int *co
if (i > 0 && j < mInputIndice[i - 1]) {
break;
}
+ // TODO: use mLengthCache instead?
length += getDistanceInt(xCoordinates[j], yCoordinates[j],
xCoordinates[j + 1], yCoordinates[j + 1]);
duration += times[j + 1] - times[j];
}
if (duration == 0 || sumDuration == 0) {
// Cannot calculate speed; thus, it gives an average value (1.0);
- mRelativeSpeeds[i] = 1.0f;
+ mSpeedRates[i] = 1.0f;
} else {
const float speed = static_cast<float>(length) / static_cast<float>(duration);
- mRelativeSpeeds[i] = speed / averageSpeed;
+ mSpeedRates[i] = speed / mAverageSpeed;
}
}
@@ -351,6 +366,69 @@ void ProximityInfoState::refreshRelativeSpeed(const int inputSize, const int *co
}
}
+void ProximityInfoState::refreshBeelineSpeedRates(const int inputSize,
+ const int *const xCoordinates, const int *const yCoordinates, const int * times) {
+ mBeelineSpeedRates.resize(mSampledInputSize);
+ for (int i = 0; i < mSampledInputSize; ++i) {
+ mBeelineSpeedRates[i] = calculateBeelineSpeedRate(
+ i, inputSize, xCoordinates, yCoordinates, times);
+ }
+}
+
+float ProximityInfoState::calculateBeelineSpeedRate(
+ const int id, const int inputSize, const int *const xCoordinates,
+ const int *const yCoordinates, const int * times) const {
+ static const int MAX_PERCENTILE = 100;
+ static const int LOOKUP_TIME_PERCENTILE = 30;
+ static const int LOOKUP_RADIUS_PERCENTILE = 50;
+ if (mSampledInputSize <= 0 || mAverageSpeed < 0.1f) {
+ return 1.0f;
+ }
+ const int lookupRadius =
+ mProximityInfo->getMostCommonKeyWidth() * LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE;
+ const int x0 = mSampledInputXs[id];
+ const int y0 = mSampledInputYs[id];
+ const int lookupTime =
+ (mTimes.back() - mTimes.front()) * LOOKUP_TIME_PERCENTILE / MAX_PERCENTILE;
+ if (lookupTime <= 0) {
+ return 1.0f;
+ }
+ int tempTime = 0;
+ int tempBeelineDistance = 0;
+ int start = mInputIndice[id];
+ // lookup forward
+ while (start > 0 && tempTime < lookupTime && tempBeelineDistance < lookupRadius) {
+ tempTime += times[start] - times[start - 1];
+ --start;
+ tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]);
+ }
+ tempTime= 0;
+ tempBeelineDistance = 0;
+ int end = mInputIndice[id];
+ // lookup backward
+ while (end < static_cast<int>(inputSize - 1) && tempTime < lookupTime
+ && tempBeelineDistance < lookupRadius) {
+ tempTime += times[end + 1] - times[end];
+ ++end;
+ tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]);
+ }
+
+ if (start == end) {
+ return 1.0f;
+ }
+
+ const int x2 = xCoordinates[start];
+ const int y2 = yCoordinates[start];
+ const int x3 = xCoordinates[end];
+ const int y3 = yCoordinates[end];
+ const int beelineDistance = getDistanceInt(x2, y2, x3, y3);
+ const int time = times[end] - times[start];
+ if (time <= 0) {
+ return 1.0f;
+ }
+ return (static_cast<float>(beelineDistance) / static_cast<float>(time)) / mAverageSpeed;
+}
+
bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize,
const int *const xCoordinates, const int *const yCoordinates, const int *const times) {
for (int i = 0; i < mSampledInputSize; ++i) {
@@ -777,7 +855,7 @@ void ProximityInfoState::updateAlignPointProbabilities(const int start) {
float skipProbability = MAX_SKIP_PROBABILITY;
const float currentAngle = getPointAngle(i);
- const float relativeSpeed = getRelativeSpeed(i);
+ const float speedRate = getSpeedRate(i);
float nearestKeyDistance = static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
for (int j = 0; j < keyCount; ++j) {
@@ -801,19 +879,19 @@ void ProximityInfoState::updateAlignPointProbabilities(const int start) {
skipProbability *= SKIP_LAST_POINT_PROBABILITY;
} else {
// If the current speed is relatively slower than adjacent keys, we promote this point.
- if (getRelativeSpeed(i - 1) - SPEED_MARGIN > relativeSpeed
- && relativeSpeed < getRelativeSpeed(i + 1) - SPEED_MARGIN) {
+ if (getSpeedRate(i - 1) - SPEED_MARGIN > speedRate
+ && speedRate < getSpeedRate(i + 1) - SPEED_MARGIN) {
if (currentAngle < CORNER_ANGLE_THRESHOLD) {
- skipProbability *= min(1.0f, relativeSpeed
+ skipProbability *= min(1.0f, speedRate
* SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY);
} else {
// If the angle is small enough, we promote this point more. (e.g. pit vs put)
- skipProbability *= min(1.0f, relativeSpeed * SPEED_WEIGHT_FOR_SKIP_PROBABILITY
+ skipProbability *= min(1.0f, speedRate * SPEED_WEIGHT_FOR_SKIP_PROBABILITY
+ MIN_SPEED_RATE_FOR_SKIP_PROBABILITY);
}
}
- skipProbability *= min(1.0f, relativeSpeed * nearestKeyDistance *
+ skipProbability *= min(1.0f, speedRate * nearestKeyDistance *
NEAREST_DISTANCE_WEIGHT + NEAREST_DISTANCE_BIAS);
// Adjusts skip probability by a rate depending on angle.
@@ -850,10 +928,10 @@ void ProximityInfoState::updateAlignPointProbabilities(const int start) {
static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION = 0.15f;
static const float MIN_STANDERD_DIVIATION = 0.37f;
- const float speedxAngleRate = min(relativeSpeed * currentAngle / M_PI_F
+ const float speedxAngleRate = min(speedRate * currentAngle / M_PI_F
* SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION,
MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION);
- const float speedxNearestKeyDistanceRate = min(relativeSpeed * nearestKeyDistance
+ const float speedxNearestKeyDistanceRate = min(speedRate * nearestKeyDistance
* SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION,
MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION);
const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate + MIN_STANDERD_DIVIATION;
@@ -932,7 +1010,7 @@ void ProximityInfoState::updateAlignPointProbabilities(const int start) {
std::stringstream sstream;
sstream << i << ", ";
sstream << "(" << mSampledInputXs[i] << ", " << mSampledInputYs[i] << "), ";
- sstream << "Speed: "<< getRelativeSpeed(i) << ", ";
+ sstream << "Speed: "<< getSpeedRate(i) << ", ";
sstream << "Angle: "<< getPointAngle(i) << ", \n";
for (hash_map_compat<int, float>::iterator it = mCharProbabilities[i].begin();
@@ -1066,5 +1144,4 @@ float ProximityInfoState::getProbability(const int index, const int keyIndex) co
}
return static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
}
-
} // namespace latinime
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index 79dd5be53..97281af1c 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -25,6 +25,7 @@
#include "char_utils.h"
#include "defines.h"
+#include "geometry_utils.h"
#include "hash_map_compat.h"
namespace latinime {
@@ -51,13 +52,13 @@ class ProximityInfoState {
// Defined here //
/////////////////////////////////////////
AK_FORCE_INLINE ProximityInfoState()
- : mProximityInfo(0), mMaxPointToKeyLength(0),
+ : mProximityInfo(0), mMaxPointToKeyLength(0.0f), mAverageSpeed(0.0f),
mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(),
mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(),
- mInputIndice(), mDistanceCache(), mLengthCache(), mRelativeSpeeds(), mDirections(),
- mCharProbabilities(), mNearKeysVector(), mSearchKeysVector(),
- mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) {
+ mInputIndice(), mLengthCache(), mDistanceCache(), mSpeedRates(),
+ mDirections(), mBeelineSpeedRates(), mCharProbabilities(), mNearKeysVector(),
+ mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) {
memset(mInputCodes, 0, sizeof(mInputCodes));
memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances));
memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
@@ -162,8 +163,12 @@ class ProximityInfoState {
int32_t getAllPossibleChars(
const size_t startIndex, int32_t *const filter, const int32_t filterSize) const;
- float getRelativeSpeed(const int index) const {
- return mRelativeSpeeds[index];
+ float getSpeedRate(const int index) const {
+ return mSpeedRates[index];
+ }
+
+ AK_FORCE_INLINE float getBeelineSpeedRate(const int id) const {
+ return mBeelineSpeedRates[id];
}
float getDirection(const int index) const {
@@ -228,12 +233,17 @@ class ProximityInfoState {
void popInputData();
void updateAlignPointProbabilities(const int start);
bool suppressCharProbabilities(const int index1, const int index2);
- void refreshRelativeSpeed(const int inputSize, const int *const xCoordinates,
+ void refreshSpeedRates(const int inputSize, const int *const xCoordinates,
const int *const yCoordinates, const int *const times, const int lastSavedInputSize);
+ void refreshBeelineSpeedRates(const int inputSize,
+ const int *const xCoordinates, const int *const yCoordinates, const int * times);
+ float calculateBeelineSpeedRate(const int id, const int inputSize,
+ const int *const xCoordinates, const int *const yCoordinates, const int * times) const;
// const
const ProximityInfo *mProximityInfo;
float mMaxPointToKeyLength;
+ float mAverageSpeed;
bool mHasTouchPositionCorrectionData;
int mMostCommonKeyWidthSquare;
std::string mLocaleStr;
@@ -248,10 +258,11 @@ class ProximityInfoState {
std::vector<int> mSampledInputYs;
std::vector<int> mTimes;
std::vector<int> mInputIndice;
+ std::vector<int> mLengthCache;
std::vector<float> mDistanceCache;
- std::vector<int> mLengthCache;
- std::vector<float> mRelativeSpeeds;
+ std::vector<float> mSpeedRates;
std::vector<float> mDirections;
+ std::vector<float> mBeelineSpeedRates;
// probabilities of skipping or mapping to a key for each point.
std::vector<hash_map_compat<int, float> > mCharProbabilities;
// The vector for the key code set which holds nearby keys for each sampled input point
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
index 8fed28f9e..2c3e3a514 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
@@ -49,6 +49,9 @@ public class PointerTrackerQueueTests extends AndroidTestCase {
}
@Override
+ public void cancelTracking() {}
+
+ @Override
public String toString() {
return Integer.toString(mId);
}