Fix detecting fast typing algorithm and parameter
Bug: 7032858 Change-Id: I5ed701e2394d16e43258a3c22d59991cb18adce8main
parent
4580b7e457
commit
3623b9767b
|
@ -144,6 +144,8 @@
|
||||||
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
|
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
|
||||||
<attr name="gestureRecognitionMinimumTime" format="integer" />
|
<attr name="gestureRecognitionMinimumTime" format="integer" />
|
||||||
<attr name="gestureRecognitionSpeedThreshold" format="fraction" />
|
<attr name="gestureRecognitionSpeedThreshold" format="fraction" />
|
||||||
|
<!-- Suppress showing key preview duration after batch input in millisecond -->
|
||||||
|
<attr name="suppressKeyPreviewAfterBatchInputDuration" format="integer" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="SuggestionStripView">
|
<declare-styleable name="SuggestionStripView">
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
false -->
|
false -->
|
||||||
<bool name="config_show_more_keys_keyboard_at_touched_point">false</bool>
|
<bool name="config_show_more_keys_keyboard_at_touched_point">false</bool>
|
||||||
<!-- Static threshold for gesture after fast typing (msec) -->
|
<!-- Static threshold for gesture after fast typing (msec) -->
|
||||||
<integer name="config_gesture_static_time_threshold_after_fast_typing">350</integer>
|
<integer name="config_gesture_static_time_threshold_after_fast_typing">1000</integer>
|
||||||
<!-- Static threshold for starting gesture detection (keyWidth%/sec) -->
|
<!-- Static threshold for starting gesture detection (keyWidth%/sec) -->
|
||||||
<fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction>
|
<fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction>
|
||||||
<!-- Dynamic threshold for gesture after fast typing (msec) -->
|
<!-- Dynamic threshold for gesture after fast typing (msec) -->
|
||||||
|
@ -86,6 +86,8 @@
|
||||||
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
|
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
|
||||||
<integer name="config_gesture_recognition_minimum_time">100</integer>
|
<integer name="config_gesture_recognition_minimum_time">100</integer>
|
||||||
<fraction name="config_gesture_recognition_speed_threshold">550%</fraction>
|
<fraction name="config_gesture_recognition_speed_threshold">550%</fraction>
|
||||||
|
<!-- Suppress showing key preview duration after batch input in millisecond -->
|
||||||
|
<integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer>
|
||||||
<!--
|
<!--
|
||||||
Configuration for auto correction
|
Configuration for auto correction
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -105,6 +105,7 @@
|
||||||
<item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
|
<item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
|
||||||
<item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</item>
|
<item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</item>
|
||||||
<item name="gestureRecognitionSpeedThreshold">@fraction/config_gesture_recognition_speed_threshold</item>
|
<item name="gestureRecognitionSpeedThreshold">@fraction/config_gesture_recognition_speed_threshold</item>
|
||||||
|
<item name="suppressKeyPreviewAfterBatchInputDuration">@integer/config_suppress_key_preview_after_batch_input_duration</item>
|
||||||
</style>
|
</style>
|
||||||
<style
|
<style
|
||||||
name="MainKeyboardView"
|
name="MainKeyboardView"
|
||||||
|
|
|
@ -82,6 +82,17 @@ import java.util.WeakHashMap;
|
||||||
* @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout
|
* @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout
|
||||||
* @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout
|
* @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout
|
||||||
* @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
|
* @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold
|
||||||
|
* @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration
|
||||||
*/
|
*/
|
||||||
public final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler,
|
public final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler,
|
||||||
SuddenJumpingTouchEventHandler.ProcessMotionEvent {
|
SuddenJumpingTouchEventHandler.ProcessMotionEvent {
|
||||||
|
|
|
@ -48,9 +48,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
private static boolean sGestureHandlingEnabledByInputField = false;
|
private static boolean sGestureHandlingEnabledByInputField = false;
|
||||||
private static boolean sGestureHandlingEnabledByUser = false;
|
private static boolean sGestureHandlingEnabledByUser = false;
|
||||||
|
|
||||||
// TODO: Move this to resource.
|
|
||||||
private static final int SUPPRESS_KEY_PREVIEW_AFTER_LAST_BATCH_INPUT_DURATION = 1000; // msec
|
|
||||||
|
|
||||||
public interface KeyEventHandler {
|
public interface KeyEventHandler {
|
||||||
/**
|
/**
|
||||||
* Get KeyDetector object that is used for this PointerTracker.
|
* Get KeyDetector object that is used for this PointerTracker.
|
||||||
|
@ -126,6 +123,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
public final int mTouchNoiseThresholdTime;
|
public final int mTouchNoiseThresholdTime;
|
||||||
public final float mTouchNoiseThresholdDistance;
|
public final float mTouchNoiseThresholdDistance;
|
||||||
public final int mTouchNoiseThresholdDistanceSquared;
|
public final int mTouchNoiseThresholdDistanceSquared;
|
||||||
|
public final int mSuppressKeyPreviewAfterBatchInputDuration;
|
||||||
|
|
||||||
public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
|
public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
|
||||||
|
|
||||||
|
@ -134,6 +132,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
mTouchNoiseThresholdTime = 0;
|
mTouchNoiseThresholdTime = 0;
|
||||||
mTouchNoiseThresholdDistance = 0.0f;
|
mTouchNoiseThresholdDistance = 0.0f;
|
||||||
mTouchNoiseThresholdDistanceSquared = 0;
|
mTouchNoiseThresholdDistanceSquared = 0;
|
||||||
|
mSuppressKeyPreviewAfterBatchInputDuration = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
|
public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
|
||||||
|
@ -146,6 +145,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
mTouchNoiseThresholdDistance = touchNouseThresholdDistance;
|
mTouchNoiseThresholdDistance = touchNouseThresholdDistance;
|
||||||
mTouchNoiseThresholdDistanceSquared =
|
mTouchNoiseThresholdDistanceSquared =
|
||||||
(int)(touchNouseThresholdDistance * touchNouseThresholdDistance);
|
(int)(touchNouseThresholdDistance * touchNouseThresholdDistance);
|
||||||
|
mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt(
|
||||||
|
R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,13 +171,80 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
private boolean mIsDetectingGesture = false; // per PointerTracker.
|
private boolean mIsDetectingGesture = false; // per PointerTracker.
|
||||||
private static boolean sInGesture = false;
|
private static boolean sInGesture = false;
|
||||||
private static long sGestureFirstDownTime;
|
private static long sGestureFirstDownTime;
|
||||||
private static long sLastBatchInputTime;
|
private static TimeRecorder sTimeRecorder;
|
||||||
private static long sLastLetterTypingUpTime;
|
|
||||||
private static final InputPointers sAggregratedPointers = new InputPointers(
|
private static final InputPointers sAggregratedPointers = new InputPointers(
|
||||||
GestureStroke.DEFAULT_CAPACITY);
|
GestureStroke.DEFAULT_CAPACITY);
|
||||||
private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers
|
private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers
|
||||||
private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers
|
private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordTyping(final long eventTime) {
|
||||||
|
mLastTypingTime = eventTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordLetterTyping(final long eventTime) {
|
||||||
|
mLastLetterTypingTime = eventTime;
|
||||||
|
// Reset gesture typing time
|
||||||
|
mLastBatchInputTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordGestureTyping(final long eventTime) {
|
||||||
|
mLastBatchInputTime = eventTime;
|
||||||
|
// Reset typing time.
|
||||||
|
mLastTypingTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInTyping() {
|
||||||
|
return mLastTypingTime != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInBatchInput() {
|
||||||
|
return mLastBatchInputTime != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCodeInput(final int code, final long eventTime) {
|
||||||
|
if (Keyboard.isLetterCode(code) && code != Keyboard.CODE_SPACE) {
|
||||||
|
if (isInTyping()
|
||||||
|
&& eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) {
|
||||||
|
recordLetterTyping(eventTime);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) {
|
||||||
|
// This non-letter typing should be treated as a part of fast typing.
|
||||||
|
recordLetterTyping(eventTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recordTyping(eventTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEndBatchInput(final long eventTime) {
|
||||||
|
recordGestureTyping(eventTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastLetterTypingTime() {
|
||||||
|
return mLastLetterTypingTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
|
||||||
|
return !isInTyping() && isInBatchInput()
|
||||||
|
&& eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The position and time at which first down event occurred.
|
// The position and time at which first down event occurred.
|
||||||
private long mDownTime;
|
private long mDownTime;
|
||||||
private long mUpTime;
|
private long mUpTime;
|
||||||
|
@ -225,11 +293,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
|
sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
|
||||||
sParams = PointerTrackerParams.DEFAULT;
|
sParams = PointerTrackerParams.DEFAULT;
|
||||||
sGestureStrokeParams = GestureStrokeParams.DEFAULT;
|
sGestureStrokeParams = GestureStrokeParams.DEFAULT;
|
||||||
|
sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setParameters(final TypedArray mainKeyboardViewAttr) {
|
public static void setParameters(final TypedArray mainKeyboardViewAttr) {
|
||||||
sParams = new PointerTrackerParams(mainKeyboardViewAttr);
|
sParams = new PointerTrackerParams(mainKeyboardViewAttr);
|
||||||
sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr);
|
sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr);
|
||||||
|
sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateGestureHandlingMode() {
|
private static void updateGestureHandlingMode() {
|
||||||
|
@ -336,7 +406,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
// 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 in shifted state and the
|
||||||
// primaryCode is different from {@link Key#mCode}.
|
// primaryCode is different from {@link Key#mCode}.
|
||||||
private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x,
|
private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x,
|
||||||
final int y) {
|
final int y, final long eventTime) {
|
||||||
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
|
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
|
||||||
final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
|
final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
|
||||||
final int code = altersCode ? key.getAltCode() : primaryCode;
|
final int code = altersCode ? key.getAltCode() : primaryCode;
|
||||||
|
@ -356,7 +426,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
}
|
}
|
||||||
// Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
|
// Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
|
||||||
if (key.isEnabled() || altersCode) {
|
if (key.isEnabled() || altersCode) {
|
||||||
sLastBatchInputTime = 0; // reset time
|
sTimeRecorder.onCodeInput(code, eventTime);
|
||||||
if (code == Keyboard.CODE_OUTPUT_TEXT) {
|
if (code == Keyboard.CODE_OUTPUT_TEXT) {
|
||||||
mListener.onTextInput(key.getOutputText());
|
mListener.onTextInput(key.getOutputText());
|
||||||
} else if (code != Keyboard.CODE_UNSPECIFIED) {
|
} else if (code != Keyboard.CODE_UNSPECIFIED) {
|
||||||
|
@ -471,10 +541,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
|
|
||||||
private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
|
private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
|
||||||
if (!sShouldHandleGesture) return false;
|
if (!sShouldHandleGesture) return false;
|
||||||
if (sLastBatchInputTime == 0) return false;
|
return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime);
|
||||||
final long elapsedTimeAfterTheLastBatchInput = eventTime - sLastBatchInputTime;
|
|
||||||
return elapsedTimeAfterTheLastBatchInput
|
|
||||||
< SUPPRESS_KEY_PREVIEW_AFTER_LAST_BATCH_INPUT_DURATION;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPressedKeyGraphics(final Key key, final long eventTime) {
|
private void setPressedKeyGraphics(final Key key, final long eventTime) {
|
||||||
|
@ -620,7 +687,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
mPointerId, sAggregratedPointers.getPointerSize()));
|
mPointerId, sAggregratedPointers.getPointerSize()));
|
||||||
}
|
}
|
||||||
sInGesture = false;
|
sInGesture = false;
|
||||||
sLastBatchInputTime = eventTime;
|
sTimeRecorder.onEndBatchInput(eventTime);
|
||||||
mListener.onEndBatchInput(sAggregratedPointers);
|
mListener.onEndBatchInput(sAggregratedPointers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -698,7 +765,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
sGestureFirstDownTime = eventTime;
|
sGestureFirstDownTime = eventTime;
|
||||||
}
|
}
|
||||||
mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime,
|
mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime,
|
||||||
sLastLetterTypingUpTime);
|
sTimeRecorder.getLastLetterTypingTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,11 +1006,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentKey != null && !currentKey.isRepeatable()) {
|
if (currentKey != null && !currentKey.isRepeatable()) {
|
||||||
detectAndSendKey(currentKey, mKeyX, mKeyY);
|
detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
|
||||||
final int code = currentKey.mCode;
|
|
||||||
if (Keyboard.isLetterCode(code) && code != Keyboard.CODE_SPACE) {
|
|
||||||
sLastLetterTypingUpTime = eventTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,7 +1057,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
|
|
||||||
public void onRegisterKey(final Key key) {
|
public void onRegisterKey(final Key key) {
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
detectAndSendKey(key, key.mX, key.mY);
|
detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
|
||||||
mTimerProxy.startTypingStateTimer(key);
|
mTimerProxy.startTypingStateTimer(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1020,14 +1083,14 @@ public final 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) {
|
if (key == null) {
|
||||||
callListenerOnCancelInput();
|
callListenerOnCancelInput();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int code = key.mCode;
|
final int code = key.mCode;
|
||||||
callListenerOnCodeInput(key, code, x, y);
|
callListenerOnCodeInput(key, code, x, y, eventTime);
|
||||||
callListenerOnRelease(key, code, false);
|
callListenerOnRelease(key, code, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue