Merge "Fix the offdevice regression test build"
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index c718332..ee4ac95 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -346,6 +346,8 @@
     // true if this pointer is in a sliding key input from a modifier key,
     // so that further modifier keys should be ignored.
     boolean mIsInSlidingKeyInputFromModifier;
+    // if not a NOT_A_CODE, the key of this code is repeating
+    private int mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
 
     // true if a sliding key input is allowed.
     private boolean mIsAllowedSlidingKeyInput;
@@ -1248,6 +1250,8 @@
         mIsDetectingGesture = false;
         final Key currentKey = mCurrentKey;
         mCurrentKey = null;
+        final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode;
+        mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
         // Release the last pressed key.
         setReleasedKeyGraphics(currentKey);
 
@@ -1273,8 +1277,8 @@
         if (mIsTrackingForActionDisabled) {
             return;
         }
-        if (currentKey != null && currentKey.isRepeatable() && !isInSlidingKeyInput) {
-            // Repeatable key has been registered in {@link #onDownEventInternal(int,int,long)}.
+        if (currentKey != null && currentKey.isRepeatable()
+                && (currentKey.getCode() == currentRepeatingKeyCode) && !isInSlidingKeyInput) {
             return;
         }
         detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
@@ -1413,7 +1417,6 @@
         if (!key.isRepeatable()) return;
         // Don't start key repeat when we are in sliding input mode.
         if (mIsInSlidingKeyInput) return;
-        detectAndSendKey(key, key.getX(), key.getY(), SystemClock.uptimeMillis());
         final int startRepeatCount = 1;
         mTimerProxy.startKeyRepeatTimer(this, startRepeatCount, sParams.mKeyRepeatStartTimeout);
     }
@@ -1421,8 +1424,10 @@
     public void onKeyRepeat(final int code, final int repeatCount) {
         final Key key = getKey();
         if (key == null || key.getCode() != code) {
+            mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
             return;
         }
+        mCurrentRepeatingKeyCode = code;
         mIsDetectingGesture = false;
         final int nextRepeatCount = repeatCount + 1;
         mTimerProxy.startKeyRepeatTimer(this, nextRepeatCount, sParams.mKeyRepeatInterval);
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 61ccfcf..fdde98d 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -35,6 +35,7 @@
 /**
  * Implements a static, compacted, binary dictionary of standard words.
  */
+// TODO: All methods which should be locked need to have a suffix "Locked".
 public final class BinaryDictionary extends Dictionary {
     private static final String TAG = BinaryDictionary.class.getSimpleName();
 
@@ -283,22 +284,23 @@
         removeBigramWordsNative(mNativeDict, codePoints0, codePoints1);
     }
 
-    public void flush() {
-        if (!isValidDictionary()) return;
-        flushNative(mNativeDict, mDictFilePath);
-        closeNative(mNativeDict);
+    private void reopen() {
+        close();
         final File dictFile = new File(mDictFilePath);
         mNativeDict = openNative(dictFile.getAbsolutePath(), 0 /* startOffset */,
                 dictFile.length(), true /* isUpdatable */);
     }
 
+    public void flush() {
+        if (!isValidDictionary()) return;
+        flushNative(mNativeDict, mDictFilePath);
+        reopen();
+    }
+
     public void flushWithGC() {
         if (!isValidDictionary()) return;
         flushWithGCNative(mNativeDict, mDictFilePath);
-        closeNative(mNativeDict);
-        final File dictFile = new File(mDictFilePath);
-        mNativeDict = openNative(dictFile.getAbsolutePath(), 0 /* startOffset */,
-                dictFile.length(), true /* isUpdatable */);
+        reopen();
     }
 
     public boolean needsToRunGC() {
@@ -338,21 +340,23 @@
                     traverseSession.close();
                 }
             }
+            mDicTraverseSessions.clear();
         }
-        closeInternal();
+        closeInternalLocked();
     }
 
-    private synchronized void closeInternal() {
+    private synchronized void closeInternalLocked() {
         if (mNativeDict != 0) {
             closeNative(mNativeDict);
             mNativeDict = 0;
         }
     }
 
+    // TODO: Manage BinaryDictionary instances without using WeakReference or something.
     @Override
     protected void finalize() throws Throwable {
         try {
-            closeInternal();
+            closeInternalLocked();
         } finally {
             super.finalize();
         }