Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3623b976 authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Fix detecting fast typing algorithm and parameter

Bug: 7032858
Change-Id: I5ed701e2394d16e43258a3c22d59991cb18adce8
parent 4580b7e4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -144,6 +144,8 @@
        <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
        <attr name="gestureRecognitionMinimumTime" format="integer" />
        <attr name="gestureRecognitionSpeedThreshold" format="fraction" />
        <!-- Suppress showing key preview duration after batch input in millisecond -->
        <attr name="suppressKeyPreviewAfterBatchInputDuration" format="integer" />
    </declare-styleable>

    <declare-styleable name="SuggestionStripView">
+3 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@
         false -->
    <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool>
    <!-- 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) -->
    <fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction>
    <!-- Dynamic threshold for gesture after fast typing (msec) -->
@@ -86,6 +86,8 @@
    <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
    <integer name="config_gesture_recognition_minimum_time">100</integer>
    <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
     -->
+1 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@
        <item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
        <item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</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
        name="MainKeyboardView"
+11 −0
Original line number Diff line number Diff line
@@ -82,6 +82,17 @@ import java.util.WeakHashMap;
 * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout
 * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout
 * @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,
        SuddenJumpingTouchEventHandler.ProcessMotionEvent {
+84 −21
Original line number Diff line number Diff line
@@ -48,9 +48,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
    private static boolean sGestureHandlingEnabledByInputField = 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 {
        /**
         * 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 float mTouchNoiseThresholdDistance;
        public final int mTouchNoiseThresholdDistanceSquared;
        public final int mSuppressKeyPreviewAfterBatchInputDuration;

        public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();

@@ -134,6 +132,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
            mTouchNoiseThresholdTime = 0;
            mTouchNoiseThresholdDistance = 0.0f;
            mTouchNoiseThresholdDistanceSquared = 0;
            mSuppressKeyPreviewAfterBatchInputDuration = 0;
        }

        public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
@@ -146,6 +145,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
            mTouchNoiseThresholdDistance = touchNouseThresholdDistance;
            mTouchNoiseThresholdDistanceSquared =
                    (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 static boolean sInGesture = false;
    private static long sGestureFirstDownTime;
    private static long sLastBatchInputTime;
    private static long sLastLetterTypingUpTime;
    private static TimeRecorder sTimeRecorder;
    private static final InputPointers sAggregratedPointers = new InputPointers(
            GestureStroke.DEFAULT_CAPACITY);
    private static int sLastRecognitionPointSize = 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.
    private long mDownTime;
    private long mUpTime;
@@ -225,11 +293,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
        sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
        sParams = PointerTrackerParams.DEFAULT;
        sGestureStrokeParams = GestureStrokeParams.DEFAULT;
        sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
    }

    public static void setParameters(final TypedArray mainKeyboardViewAttr) {
        sParams = new PointerTrackerParams(mainKeyboardViewAttr);
        sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr);
        sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
    }

    private static void updateGestureHandlingMode() {
@@ -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
    // primaryCode is different from {@link Key#mCode}.
    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 altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
        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.
        if (key.isEnabled() || altersCode) {
            sLastBatchInputTime = 0; // reset time
            sTimeRecorder.onCodeInput(code, eventTime);
            if (code == Keyboard.CODE_OUTPUT_TEXT) {
                mListener.onTextInput(key.getOutputText());
            } else if (code != Keyboard.CODE_UNSPECIFIED) {
@@ -471,10 +541,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {

    private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
        if (!sShouldHandleGesture) return false;
        if (sLastBatchInputTime == 0) return false;
        final long elapsedTimeAfterTheLastBatchInput = eventTime - sLastBatchInputTime;
        return elapsedTimeAfterTheLastBatchInput
                < SUPPRESS_KEY_PREVIEW_AFTER_LAST_BATCH_INPUT_DURATION;
        return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime);
    }

    private void setPressedKeyGraphics(final Key key, final long eventTime) {
@@ -620,7 +687,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
                            mPointerId, sAggregratedPointers.getPointerSize()));
                }
                sInGesture = false;
                sLastBatchInputTime = eventTime;
                sTimeRecorder.onEndBatchInput(eventTime);
                mListener.onEndBatchInput(sAggregratedPointers);
            }
        }
@@ -698,7 +765,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
                sGestureFirstDownTime = eventTime;
            }
            mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime,
                    sLastLetterTypingUpTime);
                    sTimeRecorder.getLastLetterTypingTime());
        }
    }

@@ -939,11 +1006,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
            return;
        }
        if (currentKey != null && !currentKey.isRepeatable()) {
            detectAndSendKey(currentKey, mKeyX, mKeyY);
            final int code = currentKey.mCode;
            if (Keyboard.isLetterCode(code) && code != Keyboard.CODE_SPACE) {
                sLastLetterTypingUpTime = eventTime;
            }
            detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
        }
    }

@@ -994,7 +1057,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {

    public void onRegisterKey(final Key key) {
        if (key != null) {
            detectAndSendKey(key, key.mX, key.mY);
            detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
            mTimerProxy.startTypingStateTimer(key);
        }
    }
@@ -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) {
            callListenerOnCancelInput();
            return;
        }

        final int code = key.mCode;
        callListenerOnCodeInput(key, code, x, y);
        callListenerOnCodeInput(key, code, x, y, eventTime);
        callListenerOnRelease(key, code, false);
    }