merge in jb-mr1-release history after reset to jb-mr1-dev
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 32b5444..b3dbb0e 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -81,7 +81,7 @@
     <integer name="config_gesture_dynamic_time_threshold_to">20</integer>
     <!-- Distance based threshold values for gesture detection (keyWidth%/sec) -->
     <fraction name="config_gesture_dynamic_distance_threshold_from">600%</fraction>
-    <fraction name="config_gesture_dynamic_distance_threshold_to">50%</fraction>
+    <fraction name="config_gesture_dynamic_distance_threshold_to">35%</fraction>
     <!-- Parameter for gesture sampling (keyWidth%/sec) -->
     <fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction>
     <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 3610533..82c77d6 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -192,32 +192,47 @@
                     gestureStrokeParams.mStaticTimeThresholdAfterFastTyping;
         }
 
-        private boolean wasLastInputTyping() {
-            return mLastTypingTime >= mLastBatchInputTime;
+        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) {
-            // Record the letter typing time when
-            // 1. Letter keys are typed successively without any batch input in between.
-            // 2. A letter key is typed within the threshold time since the last any key typing.
-            // 3. A non-letter key is typed within the threshold time since the last letter key
-            // typing.
-            if (Character.isLetter(code)) {
-                if (wasLastInputTyping()
-                        || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) {
-                    mLastLetterTypingTime = 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.
-                    mLastLetterTypingTime = eventTime;
+                    recordLetterTyping(eventTime);
                 }
             }
-            mLastTypingTime = eventTime;
+            recordTyping(eventTime);
         }
 
         public void onEndBatchInput(final long eventTime) {
-            mLastBatchInputTime = eventTime;
+            recordGestureTyping(eventTime);
         }
 
         public long getLastLetterTypingTime() {
@@ -225,7 +240,7 @@
         }
 
         public boolean needsToSuppressKeyPreviewPopup(final long eventTime) {
-            return !wasLastInputTyping()
+            return !isInTyping() && isInBatchInput()
                     && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration;
         }
     }
@@ -836,13 +851,11 @@
             // Register move event on gesture tracker.
             onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, key);
             if (sInGesture) {
+                mTimerProxy.cancelLongPressTimer();
                 mCurrentKey = null;
                 setReleasedKeyGraphics(oldKey);
                 return;
             }
-            if (mGestureStrokeWithPreviewPoints.hasDetectedFastMove()) {
-                mTimerProxy.cancelLongPressTimer();
-            }
         }
 
         if (key != null) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index c406f0c..9b1a201 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -190,8 +190,8 @@
         return mParams.mDynamicTimeThresholdFrom - decayedThreshold;
     }
 
-    public final boolean isStartOfAGesture() {
-        if (!hasDetectedFastMove()) {
+    public boolean isStartOfAGesture() {
+        if (mDetectFastMoveTime == 0) {
             return false;
         }
         final int size = mEventTimes.getLength();
@@ -200,9 +200,6 @@
         }
         final int lastIndex = size - 1;
         final int deltaTime = mEventTimes.get(lastIndex) - mDetectFastMoveTime;
-        if (deltaTime < 0) {
-            return false;
-        }
         final int deltaDistance = getDistance(
                 mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex),
                 mDetectFastMoveX, mDetectFastMoveY);
@@ -243,10 +240,6 @@
         mLastMajorEventY = y;
     }
 
-    public final boolean hasDetectedFastMove() {
-        return mDetectFastMoveTime > 0;
-    }
-
     private int detectFastMove(final int x, final int y, final int time) {
         final int size = mEventTimes.getLength();
         final int lastIndex = size - 1;
@@ -262,7 +255,7 @@
                 Log.d(TAG, String.format("[%d] detectFastMove: speed=%5.2f", mPointerId, speed));
             }
             // Equivalent to (pixels / msecs < mStartSpeedThreshold / MSEC_PER_SEC)
-            if (!hasDetectedFastMove() && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) {
+            if (mDetectFastMoveTime == 0 && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) {
                 if (DEBUG) {
                     final float speed = (float)pixelsPerSec / msecs / mKeyWidth;
                     Log.d(TAG, String.format(
@@ -313,11 +306,11 @@
         return currentTime > lastRecognitionTime + mParams.mRecognitionMinimumTime;
     }
 
-    public final void appendAllBatchPoints(final InputPointers out) {
+    public void appendAllBatchPoints(final InputPointers out) {
         appendBatchPoints(out, mEventTimes.getLength());
     }
 
-    public final void appendIncrementalBatchPoints(final InputPointers out) {
+    public void appendIncrementalBatchPoints(final InputPointers out) {
         appendBatchPoints(out, mIncrementalRecognitionSize);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 201a101..fa9f79e 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -350,7 +350,7 @@
     // of the dictionary would lose whitelist functionality.
     private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) {
         // Only for English - other languages didn't have a whitelist, hence this
-        // ad-hoc ## HACK ##
+        // ad-hock ## HACK ##
         if (!Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) return true;
 
         FileInputStream inStream = null;
diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h
index e72e7e3..53ae385 100644
--- a/native/jni/src/terminal_attributes.h
+++ b/native/jni/src/terminal_attributes.h
@@ -57,6 +57,7 @@
                 outWord[i] = (uint16_t)codePoint;
             }
             *outFreq = BinaryFormat::getAttributeFrequencyFromFlags(shortcutFlags);
+            mPos += BinaryFormat::CHARACTER_ARRAY_TERMINATOR_SIZE;
             return i;
         }
     };
diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
index 252c3d6..c31cd72 100644
--- a/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
+++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
@@ -93,7 +93,7 @@
             final FusionDictionary dict = mDictionary;
             for (final String shortcutOnly : mShortcutsMap.keySet()) {
                 if (dict.hasWord(shortcutOnly)) continue;
-                dict.add(shortcutOnly, 1, mShortcutsMap.get(shortcutOnly), true /* isNotAWord */);
+                dict.add(shortcutOnly, 0, mShortcutsMap.get(shortcutOnly), true /* isNotAWord */);
             }
             mDictionary = null;
             mShortcutsMap.clear();