Merge remote-tracking branch 'goog/master' into mergescriptpackage
This commit is contained in:
commit
cb24ea7e8a
24 changed files with 212 additions and 60 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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) {
|
||||
|
|
|
@ -125,7 +125,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
|||
}
|
||||
|
||||
private void setContextThemeWrapper(Context context, KeyboardTheme keyboardTheme) {
|
||||
if (mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) {
|
||||
if (mThemeContext == null || mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) {
|
||||
mKeyboardTheme = keyboardTheme;
|
||||
mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
|
||||
KeyboardLayoutSet.clearKeyboardCache();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -48,6 +48,9 @@ public class PointerTrackerQueueTests extends AndroidTestCase {
|
|||
mPhantomUpEventTime = eventTime + sPhantomUpCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTracking() {}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Integer.toString(mId);
|
||||
|
|
Loading…
Reference in a new issue