Loading java/src/com/android/inputmethod/keyboard/PointerTracker.java +36 −50 Original line number Diff line number Diff line Loading @@ -172,8 +172,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static long sLastLetterTypingUpTime; private static final InputPointers sAggregratedPointers = new InputPointers( GestureStroke.DEFAULT_CAPACITY); private static int sLastRecognitionPointSize = 0; private static long sLastRecognitionTime = 0; private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers // The position and time at which first down event occurred. private long mDownTime; Loading Loading @@ -310,9 +310,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, "onPress : " + KeyDetector.printableCode(key) + " ignoreModifier=" + ignoreModifierKey + " enabled=" + key.isEnabled()); Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId, KeyDetector.printableCode(key), ignoreModifierKey ? " ignoreModifier" : "", key.isEnabled() ? "" : " disabled")); } if (ignoreModifierKey) { return false; Loading @@ -335,10 +336,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); final int code = altersCode ? key.getAltCode() : primaryCode; if (DEBUG_LISTENER) { Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.getOutputText() + " x=" + x + " y=" + y + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode + " enabled=" + key.isEnabled()); final String output = code == Keyboard.CODE_OUTPUT_TEXT ? key.getOutputText() : Keyboard.printableCode(code); Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, output, ignoreModifierKey ? " ignoreModifier" : "", altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, Loading Loading @@ -367,9 +369,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode) + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + " enabled="+ key.isEnabled()); Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, Keyboard.printableCode(primaryCode), withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", key.isEnabled() ? "": " disabled")); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, Loading @@ -385,7 +388,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private void callListenerOnCancelInput() { if (DEBUG_LISTENER) { Log.d(TAG, "onCancelInput"); Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_callListenerOnCancelInput(); Loading @@ -394,6 +397,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void setKeyDetectorInner(final KeyDetector keyDetector) { final Keyboard keyboard = keyDetector.getKeyboard(); if (keyDetector == mKeyDetector && keyboard == mKeyboard) { return; } mKeyDetector = keyDetector; mKeyboard = keyDetector.getKeyboard(); mGestureStrokeWithPreviewPoints.setKeyboardGeometry(mKeyboard.mMostCommonKeyWidth); Loading Loading @@ -564,10 +571,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return; } if (DEBUG_LISTENER) { Log.d(TAG, "onStartBatchInput"); Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); } sInGesture = true; synchronized (sAggregratedPointers) { sAggregratedPointers.reset(); sLastRecognitionPointSize = 0; sLastRecognitionTime = 0; mListener.onStartBatchInput(); } final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); } Loading @@ -582,7 +594,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { sLastRecognitionPointSize = size; sLastRecognitionTime = eventTime; if (DEBUG_LISTENER) { Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size); Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, size)); } mListener.onUpdateBatchInput(sAggregratedPointers); } Loading @@ -595,37 +608,20 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private void mayEndBatchInput(final long eventTime) { synchronized (sAggregratedPointers) { mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); mGestureStrokeWithPreviewPoints.reset(); if (getActivePointerTrackerCount() == 1) { if (DEBUG_LISTENER) { Log.d(TAG, "onEndBatchInput: batchPoints=" + sAggregratedPointers.getPointerSize()); Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", mPointerId, sAggregratedPointers.getPointerSize())); } sInGesture = false; sLastBatchInputTime = eventTime; mListener.onEndBatchInput(sAggregratedPointers); clearBatchInputPointsOfAllPointerTrackers(); } } final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); } private static void abortBatchInput() { clearBatchInputPointsOfAllPointerTrackers(); } private static void clearBatchInputPointsOfAllPointerTrackers() { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); tracker.mGestureStrokeWithPreviewPoints.reset(); } sAggregratedPointers.reset(); sLastRecognitionPointSize = 0; sLastRecognitionTime = 0; } public void processMotionEvent(final int action, final int x, final int y, final long eventTime, final KeyEventHandler handler) { switch (action) { Loading Loading @@ -695,18 +691,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (getActivePointerTrackerCount() == 1) { sGestureFirstDownTime = eventTime; } onGestureDownEvent(x, y, eventTime); mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, sLastLetterTypingUpTime); } } private void onGestureDownEvent(final int x, final int y, final long eventTime) { mIsDetectingGesture = true; mGestureStrokeWithPreviewPoints.setLastLetterTypingTime(eventTime, sLastLetterTypingUpTime); final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); } private void onDownEventInternal(final int x, final int y, final long eventTime) { Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding Loading Loading @@ -939,9 +928,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mayEndBatchInput(eventTime); return; } // This event will be recognized as a regular code input. Clear unused possible batch points // so they are not mistakenly displayed as preview. clearBatchInputPointsOfAllPointerTrackers(); if (mKeyAlreadyProcessed) { return; } Loading @@ -955,7 +942,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) { abortBatchInput(); onLongPressed(); mIsShowingMoreKeysPanel = true; onDownEvent(x, y, SystemClock.uptimeMillis(), handler); Loading Loading @@ -1043,7 +1029,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final long eventTime) { final Key key = mKeyDetector.detectHitKey(x, y); final String code = KeyDetector.printableCode(key); Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, eventTime, code)); Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code)); } } java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +102 −64 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.inputmethod.latin.ResizableIntArray; public class GestureStroke { private static final String TAG = GestureStroke.class.getSimpleName(); private static final boolean DEBUG = false; private static final boolean DEBUG_SPEED = false; public static final int DEFAULT_CAPACITY = 128; Loading @@ -29,42 +30,52 @@ public class GestureStroke { private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; private long mLastMajorEventTime; private int mLastMajorEventX; private int mLastMajorEventY; private boolean mAfterFastTyping; private int mKeyWidth; private int mStartGestureLengthThresholdAfterFastTyping; // pixel private int mStartGestureLengthThreshold; // pixel private int mMinGestureSamplingLength; // pixel private int mGestureRecognitionSpeedThreshold; // pixel / sec private int mKeyWidth; // pixel // Static threshold for starting gesture detection private int mDetectFastMoveSpeedThreshold; // pixel /sec private int mDetectFastMoveTime; private int mDetectFastMoveX; private int mDetectFastMoveY; // Dynamic threshold for gesture after fast typing private boolean mAfterFastTyping; private int mGestureDynamicDistanceThresholdFrom; // pixel private int mGestureDynamicDistanceThresholdTo; // pixel // Variables for gesture sampling private int mGestureSamplingMinimumDistance; // pixel private long mLastMajorEventTime; private int mLastMajorEventX; private int mLastMajorEventY; // Variables for gesture recognition private int mGestureRecognitionSpeedThreshold; // pixel / sec private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; // TODO: Move some of these to resource. private static final int GESTURE_AFTER_FAST_TYPING_DURATION_THRESHOLD = 350; // msec private static final float START_GESTURE_LENGTH_THRESHOLD_AFTER_FAST_TYPING_RATIO_TO_KEY_WIDTH = 8.0f; private static final int START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION = 400; // msec private static final float START_GESTURE_LENGTH_THRESHOLD_RATIO_TO_KEY_WIDTH = 0.6f; private static final int START_GESTURE_DURATION_THRESHOLD = 70; // msec private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f; private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH = 5.5f; // keyWidth / sec private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH = 5.0f; // keyWidth / sec private static final int MSEC_PER_SEC = 1000; public static final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { return currentTime > lastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME; } // Static threshold for gesture after fast typing public static final int GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING = 350; // msec // Static threshold for starting gesture detection private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD = 1.5f; // keyWidth / sec // Dynamic threshold for gesture after fast typing private static final int GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION = 450; // msec // Time based threshold values private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_FROM = 300; // msec private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_TO = 20; // msec // Distance based threshold values private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM = 6.0f; // keyWidth private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO = 0.35f; // keyWidth // Parameters for gesture sampling private static final float GESTURE_SAMPLING_MINIMUM_DISTANCE = 1.0f / 6.0f; // keyWidth // Parameters for gesture recognition private static final int GESTURE_RECOGNITION_MINIMUM_TIME = 100; // msec private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD = 5.5f; // keyWidth / sec private static final int MSEC_PER_SEC = 1000; public GestureStroke(final int pointerId) { mPointerId = pointerId; Loading @@ -73,41 +84,58 @@ public class GestureStroke { public void setKeyboardGeometry(final int keyWidth) { mKeyWidth = keyWidth; // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? mStartGestureLengthThresholdAfterFastTyping = (int)(keyWidth * START_GESTURE_LENGTH_THRESHOLD_AFTER_FAST_TYPING_RATIO_TO_KEY_WIDTH); mStartGestureLengthThreshold = (int)(keyWidth * START_GESTURE_LENGTH_THRESHOLD_RATIO_TO_KEY_WIDTH); mMinGestureSamplingLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH); mDetectFastMoveSpeedThreshold = (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD); mGestureDynamicDistanceThresholdFrom = (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM); mGestureDynamicDistanceThresholdTo = (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO); mGestureSamplingMinimumDistance = (int)(keyWidth * GESTURE_SAMPLING_MINIMUM_DISTANCE); mGestureRecognitionSpeedThreshold = (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH); mDetectFastMoveSpeedThreshold = (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH); (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD); if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] setKeyboardGeometry: keyWidth=" + keyWidth + " tL0=" + mStartGestureLengthThresholdAfterFastTyping + " tL=" + mStartGestureLengthThreshold); Log.d(TAG, String.format( "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d", mPointerId, keyWidth, GESTURE_DYNAMIC_TIME_THRESHOLD_FROM, GESTURE_DYNAMIC_TIME_THRESHOLD_TO, mGestureDynamicDistanceThresholdFrom, mGestureDynamicDistanceThresholdTo)); } } public void setLastLetterTypingTime(final long downTime, final long lastTypingTime) { final long elpasedTimeAfterTyping = downTime - lastTypingTime; if (elpasedTimeAfterTyping < GESTURE_AFTER_FAST_TYPING_DURATION_THRESHOLD) { public void onDownEvent(final int x, final int y, final long downTime, final long gestureFirstDownTime, final long lastTypingTime) { reset(); final long elapsedTimeAfterTyping = downTime - lastTypingTime; if (elapsedTimeAfterTyping < GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING) { mAfterFastTyping = true; } if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] setLastTypingTime: dT=" + elpasedTimeAfterTyping + " afterFastTyping=" + mAfterFastTyping); Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId, elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : "")); } final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime); addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); } private int getStartGestureLengthThreshold(final int deltaTime) { if (!mAfterFastTyping || deltaTime >= START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION) { return mStartGestureLengthThreshold; private int getGestureDynamicDistanceThreshold(final int deltaTime) { if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) { return mGestureDynamicDistanceThresholdTo; } final int decayedThreshold = (mStartGestureLengthThresholdAfterFastTyping - mStartGestureLengthThreshold) * deltaTime / START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION; return mStartGestureLengthThresholdAfterFastTyping - decayedThreshold; (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo) * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION; return mGestureDynamicDistanceThresholdFrom - decayedThreshold; } private int getGestureDynamicTimeThreshold(final int deltaTime) { if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) { return GESTURE_DYNAMIC_TIME_THRESHOLD_TO; } final int decayedThreshold = (GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - GESTURE_DYNAMIC_TIME_THRESHOLD_TO) * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION; return GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - decayedThreshold; } public boolean isStartOfAGesture() { Loading @@ -120,21 +148,24 @@ public class GestureStroke { } final int lastIndex = size - 1; final int deltaTime = mEventTimes.get(lastIndex) - mDetectFastMoveTime; final int deltaLength = getDistance( final int deltaDistance = getDistance( mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), mDetectFastMoveX, mDetectFastMoveY); final int startGestureLengthThreshold = getStartGestureLengthThreshold(deltaTime); final boolean isStartOfAGesture = deltaTime > START_GESTURE_DURATION_THRESHOLD && deltaLength > startGestureLengthThreshold; final int distanceThreshold = getGestureDynamicDistanceThreshold(deltaTime); final int timeThreshold = getGestureDynamicTimeThreshold(deltaTime); final boolean isStartOfAGesture = deltaTime >= timeThreshold && deltaDistance >= distanceThreshold; if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] isStartOfAGesture: dT=" + deltaTime + " dL=" + deltaLength + " tL=" + startGestureLengthThreshold + " points=" + size + (isStartOfAGesture ? " Detect start of a gesture" : "")); Log.d(TAG, String.format("[%d] isStartOfAGesture: dT=%3d tT=%3d dD=%3d tD=%3d%s%s", mPointerId, deltaTime, timeThreshold, deltaDistance, distanceThreshold, mAfterFastTyping ? " afterFastTyping" : "", isStartOfAGesture ? " startOfAGesture" : "")); } return isStartOfAGesture; } public void reset() { protected void reset() { mIncrementalRecognitionSize = 0; mLastIncrementalBatchSize = 0; mEventTimes.setLength(0); Loading Loading @@ -167,15 +198,17 @@ public class GestureStroke { if (msecs > 0) { final int pixels = getDistance(lastX, lastY, x, y); final int pixelsPerSec = pixels * MSEC_PER_SEC; if (DEBUG) { if (DEBUG_SPEED) { final float speed = (float)pixelsPerSec / msecs / mKeyWidth; Log.d(TAG, String.format("[" + mPointerId + "] speed=%.3f", speed)); Log.d(TAG, String.format("[%d] detectFastMove: speed=%5.2f", mPointerId, speed)); } // Equivalent to (pixels / msecs < mStartSpeedThreshold / MSEC_PER_SEC) if (mDetectFastMoveTime == 0 && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) { if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] detect fast move: T=" + time + " points = " + size); final float speed = (float)pixelsPerSec / msecs / mKeyWidth; Log.d(TAG, String.format( "[%d] detectFastMove: speed=%5.2f T=%3d points=%3d fastMove", mPointerId, speed, time, size)); } mDetectFastMoveTime = time; mDetectFastMoveX = x; Loading @@ -192,8 +225,8 @@ public class GestureStroke { appendPoint(x, y, time); updateMajorEvent(x, y, time); } else { final int dist = detectFastMove(x, y, time); if (dist > mMinGestureSamplingLength) { final int distance = detectFastMove(x, y, time); if (distance > mGestureSamplingMinimumDistance) { appendPoint(x, y, time); } } Loading @@ -216,6 +249,11 @@ public class GestureStroke { } } public static final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { return currentTime > lastRecognitionTime + GESTURE_RECOGNITION_MINIMUM_TIME; } public void appendAllBatchPoints(final InputPointers out) { appendBatchPoints(out, mEventTimes.getLength()); } Loading java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { } @Override public void reset() { protected void reset() { super.reset(); mStrokeId++; mLastPreviewSize = 0; Loading java/src/com/android/inputmethod/latin/LatinIME.java +33 −14 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
java/src/com/android/inputmethod/keyboard/PointerTracker.java +36 −50 Original line number Diff line number Diff line Loading @@ -172,8 +172,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private static long sLastLetterTypingUpTime; private static final InputPointers sAggregratedPointers = new InputPointers( GestureStroke.DEFAULT_CAPACITY); private static int sLastRecognitionPointSize = 0; private static long sLastRecognitionTime = 0; private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers // The position and time at which first down event occurred. private long mDownTime; Loading Loading @@ -310,9 +310,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, "onPress : " + KeyDetector.printableCode(key) + " ignoreModifier=" + ignoreModifierKey + " enabled=" + key.isEnabled()); Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId, KeyDetector.printableCode(key), ignoreModifierKey ? " ignoreModifier" : "", key.isEnabled() ? "" : " disabled")); } if (ignoreModifierKey) { return false; Loading @@ -335,10 +336,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); final int code = altersCode ? key.getAltCode() : primaryCode; if (DEBUG_LISTENER) { Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.getOutputText() + " x=" + x + " y=" + y + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode + " enabled=" + key.isEnabled()); final String output = code == Keyboard.CODE_OUTPUT_TEXT ? key.getOutputText() : Keyboard.printableCode(code); Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, output, ignoreModifierKey ? " ignoreModifier" : "", altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, Loading Loading @@ -367,9 +369,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode) + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + " enabled="+ key.isEnabled()); Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, Keyboard.printableCode(primaryCode), withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", key.isEnabled() ? "": " disabled")); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, Loading @@ -385,7 +388,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private void callListenerOnCancelInput() { if (DEBUG_LISTENER) { Log.d(TAG, "onCancelInput"); Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_callListenerOnCancelInput(); Loading @@ -394,6 +397,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void setKeyDetectorInner(final KeyDetector keyDetector) { final Keyboard keyboard = keyDetector.getKeyboard(); if (keyDetector == mKeyDetector && keyboard == mKeyboard) { return; } mKeyDetector = keyDetector; mKeyboard = keyDetector.getKeyboard(); mGestureStrokeWithPreviewPoints.setKeyboardGeometry(mKeyboard.mMostCommonKeyWidth); Loading Loading @@ -564,10 +571,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return; } if (DEBUG_LISTENER) { Log.d(TAG, "onStartBatchInput"); Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); } sInGesture = true; synchronized (sAggregratedPointers) { sAggregratedPointers.reset(); sLastRecognitionPointSize = 0; sLastRecognitionTime = 0; mListener.onStartBatchInput(); } final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); } Loading @@ -582,7 +594,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { sLastRecognitionPointSize = size; sLastRecognitionTime = eventTime; if (DEBUG_LISTENER) { Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size); Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, size)); } mListener.onUpdateBatchInput(sAggregratedPointers); } Loading @@ -595,37 +608,20 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private void mayEndBatchInput(final long eventTime) { synchronized (sAggregratedPointers) { mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); mGestureStrokeWithPreviewPoints.reset(); if (getActivePointerTrackerCount() == 1) { if (DEBUG_LISTENER) { Log.d(TAG, "onEndBatchInput: batchPoints=" + sAggregratedPointers.getPointerSize()); Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", mPointerId, sAggregratedPointers.getPointerSize())); } sInGesture = false; sLastBatchInputTime = eventTime; mListener.onEndBatchInput(sAggregratedPointers); clearBatchInputPointsOfAllPointerTrackers(); } } final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); } private static void abortBatchInput() { clearBatchInputPointsOfAllPointerTrackers(); } private static void clearBatchInputPointsOfAllPointerTrackers() { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); tracker.mGestureStrokeWithPreviewPoints.reset(); } sAggregratedPointers.reset(); sLastRecognitionPointSize = 0; sLastRecognitionTime = 0; } public void processMotionEvent(final int action, final int x, final int y, final long eventTime, final KeyEventHandler handler) { switch (action) { Loading Loading @@ -695,18 +691,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (getActivePointerTrackerCount() == 1) { sGestureFirstDownTime = eventTime; } onGestureDownEvent(x, y, eventTime); mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, sLastLetterTypingUpTime); } } private void onGestureDownEvent(final int x, final int y, final long eventTime) { mIsDetectingGesture = true; mGestureStrokeWithPreviewPoints.setLastLetterTypingTime(eventTime, sLastLetterTypingUpTime); final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); } private void onDownEventInternal(final int x, final int y, final long eventTime) { Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding Loading Loading @@ -939,9 +928,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mayEndBatchInput(eventTime); return; } // This event will be recognized as a regular code input. Clear unused possible batch points // so they are not mistakenly displayed as preview. clearBatchInputPointsOfAllPointerTrackers(); if (mKeyAlreadyProcessed) { return; } Loading @@ -955,7 +942,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) { abortBatchInput(); onLongPressed(); mIsShowingMoreKeysPanel = true; onDownEvent(x, y, SystemClock.uptimeMillis(), handler); Loading Loading @@ -1043,7 +1029,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final long eventTime) { final Key key = mKeyDetector.detectHitKey(x, y); final String code = KeyDetector.printableCode(key); Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, eventTime, code)); Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code)); } }
java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +102 −64 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.inputmethod.latin.ResizableIntArray; public class GestureStroke { private static final String TAG = GestureStroke.class.getSimpleName(); private static final boolean DEBUG = false; private static final boolean DEBUG_SPEED = false; public static final int DEFAULT_CAPACITY = 128; Loading @@ -29,42 +30,52 @@ public class GestureStroke { private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; private long mLastMajorEventTime; private int mLastMajorEventX; private int mLastMajorEventY; private boolean mAfterFastTyping; private int mKeyWidth; private int mStartGestureLengthThresholdAfterFastTyping; // pixel private int mStartGestureLengthThreshold; // pixel private int mMinGestureSamplingLength; // pixel private int mGestureRecognitionSpeedThreshold; // pixel / sec private int mKeyWidth; // pixel // Static threshold for starting gesture detection private int mDetectFastMoveSpeedThreshold; // pixel /sec private int mDetectFastMoveTime; private int mDetectFastMoveX; private int mDetectFastMoveY; // Dynamic threshold for gesture after fast typing private boolean mAfterFastTyping; private int mGestureDynamicDistanceThresholdFrom; // pixel private int mGestureDynamicDistanceThresholdTo; // pixel // Variables for gesture sampling private int mGestureSamplingMinimumDistance; // pixel private long mLastMajorEventTime; private int mLastMajorEventX; private int mLastMajorEventY; // Variables for gesture recognition private int mGestureRecognitionSpeedThreshold; // pixel / sec private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; // TODO: Move some of these to resource. private static final int GESTURE_AFTER_FAST_TYPING_DURATION_THRESHOLD = 350; // msec private static final float START_GESTURE_LENGTH_THRESHOLD_AFTER_FAST_TYPING_RATIO_TO_KEY_WIDTH = 8.0f; private static final int START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION = 400; // msec private static final float START_GESTURE_LENGTH_THRESHOLD_RATIO_TO_KEY_WIDTH = 0.6f; private static final int START_GESTURE_DURATION_THRESHOLD = 70; // msec private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f; private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH = 5.5f; // keyWidth / sec private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH = 5.0f; // keyWidth / sec private static final int MSEC_PER_SEC = 1000; public static final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { return currentTime > lastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME; } // Static threshold for gesture after fast typing public static final int GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING = 350; // msec // Static threshold for starting gesture detection private static final float DETECT_FAST_MOVE_SPEED_THRESHOLD = 1.5f; // keyWidth / sec // Dynamic threshold for gesture after fast typing private static final int GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION = 450; // msec // Time based threshold values private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_FROM = 300; // msec private static final int GESTURE_DYNAMIC_TIME_THRESHOLD_TO = 20; // msec // Distance based threshold values private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM = 6.0f; // keyWidth private static final float GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO = 0.35f; // keyWidth // Parameters for gesture sampling private static final float GESTURE_SAMPLING_MINIMUM_DISTANCE = 1.0f / 6.0f; // keyWidth // Parameters for gesture recognition private static final int GESTURE_RECOGNITION_MINIMUM_TIME = 100; // msec private static final float GESTURE_RECOGNITION_SPEED_THRESHOLD = 5.5f; // keyWidth / sec private static final int MSEC_PER_SEC = 1000; public GestureStroke(final int pointerId) { mPointerId = pointerId; Loading @@ -73,41 +84,58 @@ public class GestureStroke { public void setKeyboardGeometry(final int keyWidth) { mKeyWidth = keyWidth; // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? mStartGestureLengthThresholdAfterFastTyping = (int)(keyWidth * START_GESTURE_LENGTH_THRESHOLD_AFTER_FAST_TYPING_RATIO_TO_KEY_WIDTH); mStartGestureLengthThreshold = (int)(keyWidth * START_GESTURE_LENGTH_THRESHOLD_RATIO_TO_KEY_WIDTH); mMinGestureSamplingLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH); mDetectFastMoveSpeedThreshold = (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD); mGestureDynamicDistanceThresholdFrom = (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_FROM); mGestureDynamicDistanceThresholdTo = (int)(keyWidth * GESTURE_DYNAMIC_DISTANCE_THRESHOLD_TO); mGestureSamplingMinimumDistance = (int)(keyWidth * GESTURE_SAMPLING_MINIMUM_DISTANCE); mGestureRecognitionSpeedThreshold = (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH); mDetectFastMoveSpeedThreshold = (int)(keyWidth * DETECT_FAST_MOVE_SPEED_THRESHOLD_RATIO_TO_KEY_WIDTH); (int)(keyWidth * GESTURE_RECOGNITION_SPEED_THRESHOLD); if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] setKeyboardGeometry: keyWidth=" + keyWidth + " tL0=" + mStartGestureLengthThresholdAfterFastTyping + " tL=" + mStartGestureLengthThreshold); Log.d(TAG, String.format( "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d", mPointerId, keyWidth, GESTURE_DYNAMIC_TIME_THRESHOLD_FROM, GESTURE_DYNAMIC_TIME_THRESHOLD_TO, mGestureDynamicDistanceThresholdFrom, mGestureDynamicDistanceThresholdTo)); } } public void setLastLetterTypingTime(final long downTime, final long lastTypingTime) { final long elpasedTimeAfterTyping = downTime - lastTypingTime; if (elpasedTimeAfterTyping < GESTURE_AFTER_FAST_TYPING_DURATION_THRESHOLD) { public void onDownEvent(final int x, final int y, final long downTime, final long gestureFirstDownTime, final long lastTypingTime) { reset(); final long elapsedTimeAfterTyping = downTime - lastTypingTime; if (elapsedTimeAfterTyping < GESTURE_STATIC_TIME_THRESHOLD_AFTER_FAST_TYPING) { mAfterFastTyping = true; } if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] setLastTypingTime: dT=" + elpasedTimeAfterTyping + " afterFastTyping=" + mAfterFastTyping); Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId, elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : "")); } final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime); addPoint(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); } private int getStartGestureLengthThreshold(final int deltaTime) { if (!mAfterFastTyping || deltaTime >= START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION) { return mStartGestureLengthThreshold; private int getGestureDynamicDistanceThreshold(final int deltaTime) { if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) { return mGestureDynamicDistanceThresholdTo; } final int decayedThreshold = (mStartGestureLengthThresholdAfterFastTyping - mStartGestureLengthThreshold) * deltaTime / START_GESTURE_LENGTH_THRESHOLD_DECAY_DURATION; return mStartGestureLengthThresholdAfterFastTyping - decayedThreshold; (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo) * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION; return mGestureDynamicDistanceThresholdFrom - decayedThreshold; } private int getGestureDynamicTimeThreshold(final int deltaTime) { if (!mAfterFastTyping || deltaTime >= GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION) { return GESTURE_DYNAMIC_TIME_THRESHOLD_TO; } final int decayedThreshold = (GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - GESTURE_DYNAMIC_TIME_THRESHOLD_TO) * deltaTime / GESTURE_DYNAMIC_THRESHOLD_DECAY_DURATION; return GESTURE_DYNAMIC_TIME_THRESHOLD_FROM - decayedThreshold; } public boolean isStartOfAGesture() { Loading @@ -120,21 +148,24 @@ public class GestureStroke { } final int lastIndex = size - 1; final int deltaTime = mEventTimes.get(lastIndex) - mDetectFastMoveTime; final int deltaLength = getDistance( final int deltaDistance = getDistance( mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), mDetectFastMoveX, mDetectFastMoveY); final int startGestureLengthThreshold = getStartGestureLengthThreshold(deltaTime); final boolean isStartOfAGesture = deltaTime > START_GESTURE_DURATION_THRESHOLD && deltaLength > startGestureLengthThreshold; final int distanceThreshold = getGestureDynamicDistanceThreshold(deltaTime); final int timeThreshold = getGestureDynamicTimeThreshold(deltaTime); final boolean isStartOfAGesture = deltaTime >= timeThreshold && deltaDistance >= distanceThreshold; if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] isStartOfAGesture: dT=" + deltaTime + " dL=" + deltaLength + " tL=" + startGestureLengthThreshold + " points=" + size + (isStartOfAGesture ? " Detect start of a gesture" : "")); Log.d(TAG, String.format("[%d] isStartOfAGesture: dT=%3d tT=%3d dD=%3d tD=%3d%s%s", mPointerId, deltaTime, timeThreshold, deltaDistance, distanceThreshold, mAfterFastTyping ? " afterFastTyping" : "", isStartOfAGesture ? " startOfAGesture" : "")); } return isStartOfAGesture; } public void reset() { protected void reset() { mIncrementalRecognitionSize = 0; mLastIncrementalBatchSize = 0; mEventTimes.setLength(0); Loading Loading @@ -167,15 +198,17 @@ public class GestureStroke { if (msecs > 0) { final int pixels = getDistance(lastX, lastY, x, y); final int pixelsPerSec = pixels * MSEC_PER_SEC; if (DEBUG) { if (DEBUG_SPEED) { final float speed = (float)pixelsPerSec / msecs / mKeyWidth; Log.d(TAG, String.format("[" + mPointerId + "] speed=%.3f", speed)); Log.d(TAG, String.format("[%d] detectFastMove: speed=%5.2f", mPointerId, speed)); } // Equivalent to (pixels / msecs < mStartSpeedThreshold / MSEC_PER_SEC) if (mDetectFastMoveTime == 0 && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) { if (DEBUG) { Log.d(TAG, "[" + mPointerId + "] detect fast move: T=" + time + " points = " + size); final float speed = (float)pixelsPerSec / msecs / mKeyWidth; Log.d(TAG, String.format( "[%d] detectFastMove: speed=%5.2f T=%3d points=%3d fastMove", mPointerId, speed, time, size)); } mDetectFastMoveTime = time; mDetectFastMoveX = x; Loading @@ -192,8 +225,8 @@ public class GestureStroke { appendPoint(x, y, time); updateMajorEvent(x, y, time); } else { final int dist = detectFastMove(x, y, time); if (dist > mMinGestureSamplingLength) { final int distance = detectFastMove(x, y, time); if (distance > mGestureSamplingMinimumDistance) { appendPoint(x, y, time); } } Loading @@ -216,6 +249,11 @@ public class GestureStroke { } } public static final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { return currentTime > lastRecognitionTime + GESTURE_RECOGNITION_MINIMUM_TIME; } public void appendAllBatchPoints(final InputPointers out) { appendBatchPoints(out, mEventTimes.getLength()); } Loading
java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { } @Override public void reset() { protected void reset() { super.reset(); mStrokeId++; mLastPreviewSize = 0; Loading
java/src/com/android/inputmethod/latin/LatinIME.java +33 −14 File changed.Preview size limit exceeded, changes collapsed. Show changes