Merge "Fix gesture detection algorithm" into jb-mr1-dev
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 100a9c6..ad7d0a3 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -47,6 +47,9 @@
     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.
@@ -165,6 +168,7 @@
     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 final InputPointers sAggregratedPointers = new InputPointers(
             GestureStroke.DEFAULT_CAPACITY);
@@ -347,6 +351,7 @@
         }
         // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
         if (key.isEnabled() || altersCode) {
+            sLastBatchInputTime = 0; // reset time
             if (code == Keyboard.CODE_OUTPUT_TEXT) {
                 mListener.onTextInput(key.getOutputText());
             } else if (code != Keyboard.CODE_UNSPECIFIED) {
@@ -459,7 +464,15 @@
         }
     }
 
-    private void setPressedKeyGraphics(final Key key) {
+    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;
+    }
+
+    private void setPressedKeyGraphics(final Key key, final long eventTime) {
         if (key == null) {
             return;
         }
@@ -471,7 +484,7 @@
             return;
         }
 
-        if (!key.noKeyPreview() && !sInGesture) {
+        if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) {
             mDrawingProxy.showKeyPreview(this);
         }
         updatePressKeyGraphics(key);
@@ -592,7 +605,7 @@
         mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker);
     }
 
-    private void mayEndBatchInput() {
+    private void mayEndBatchInput(final long eventTime) {
         synchronized (sAggregratedPointers) {
             mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers);
             if (getActivePointerTrackerCount() == 1) {
@@ -601,6 +614,7 @@
                             mPointerId, sAggregratedPointers.getPointerSize()));
                 }
                 sInGesture = false;
+                sLastBatchInputTime = eventTime;
                 mListener.onEndBatchInput(sAggregratedPointers);
             }
         }
@@ -703,7 +717,7 @@
 
             startRepeatKey(key);
             startLongPressTimer(key);
-            setPressedKeyGraphics(key);
+            setPressedKeyGraphics(key, eventTime);
         }
     }
 
@@ -781,7 +795,7 @@
                 }
                 onMoveToNewKey(key, x, y);
                 startLongPressTimer(key);
-                setPressedKeyGraphics(key);
+                setPressedKeyGraphics(key, eventTime);
             } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) {
                 // The pointer has been slid in to the new key from the previous key, we must call
                 // onRelease() first to notify that the previous key has been released, then call
@@ -800,7 +814,7 @@
                     }
                     onMoveToNewKey(key, x, y);
                     startLongPressTimer(key);
-                    setPressedKeyGraphics(key);
+                    setPressedKeyGraphics(key, eventTime);
                 } else {
                     // HACK: On some devices, quick successive touches may be translated to sudden
                     // move by touch panel firmware. This hack detects the case and translates the
@@ -911,7 +925,7 @@
             if (currentKey != null) {
                 callListenerOnRelease(currentKey, currentKey.mCode, true);
             }
-            mayEndBatchInput();
+            mayEndBatchInput(eventTime);
             return;
         }