Merge "Pass traverse session" into jb-mr1-dev
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 3abe890..9198500 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -219,6 +219,11 @@
         return code >= CODE_SPACE;
     }
 
+    @Override
+    public String toString() {
+        return mId.toString();
+    }
+
     public static class Params {
         public KeyboardId mId;
         public int mThemeId;
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 184011f..2b90a3c 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -34,7 +34,7 @@
 
 import java.util.ArrayList;
 
-public class PointerTracker implements PointerTrackerQueue.ElementActions {
+public class PointerTracker implements PointerTrackerQueue.Element {
     private static final String TAG = PointerTracker.class.getSimpleName();
     private static final boolean DEBUG_EVENT = false;
     private static final boolean DEBUG_MOVE_EVENT = false;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
index bd16480..1c7ceaf 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
@@ -18,85 +18,146 @@
 
 import android.util.Log;
 
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.ArrayList;
 
 public class PointerTrackerQueue {
     private static final String TAG = PointerTrackerQueue.class.getSimpleName();
     private static final boolean DEBUG = false;
 
-    public interface ElementActions {
+    public interface Element {
         public boolean isModifier();
         public boolean isInSlidingKeyInput();
         public void onPhantomUpEvent(long eventTime);
     }
 
-    // TODO: Use ring buffer instead of {@link LinkedList}.
-    private final LinkedList<ElementActions> mQueue = new LinkedList<ElementActions>();
+    private static final int INITIAL_CAPACITY = 10;
+    private final ArrayList<Element> mExpandableArrayOfActivePointers =
+            new ArrayList<Element>(INITIAL_CAPACITY);
+    private int mArraySize = 0;
 
-    public int size() {
-        return mQueue.size();
+    public synchronized int size() {
+        return mArraySize;
     }
 
-    public synchronized void add(ElementActions tracker) {
-        mQueue.add(tracker);
+    public synchronized void add(final Element pointer) {
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        if (arraySize < expandableArray.size()) {
+            expandableArray.set(arraySize, pointer);
+        } else {
+            expandableArray.add(pointer);
+        }
+        mArraySize = arraySize + 1;
     }
 
-    public synchronized void remove(ElementActions tracker) {
-        mQueue.remove(tracker);
+    public synchronized void remove(final Element pointer) {
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        int newSize = 0;
+        for (int index = 0; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
+            if (element == pointer) {
+                if (newSize != index) {
+                    Log.w(TAG, "Found duplicated element in remove: " + pointer);
+                }
+                continue; // Remove this element from the expandableArray.
+            }
+            if (newSize != index) {
+                // Shift this element toward the beginning of the expandableArray.
+                expandableArray.set(newSize, element);
+            }
+            newSize++;
+        }
+        mArraySize = newSize;
     }
 
-    public synchronized void releaseAllPointersOlderThan(ElementActions tracker,
-            long eventTime) {
+    public synchronized void releaseAllPointersOlderThan(final Element pointer,
+            final long eventTime) {
         if (DEBUG) {
-            Log.d(TAG, "releaseAllPoniterOlderThan: " + tracker + " " + this);
+            Log.d(TAG, "releaseAllPoniterOlderThan: " + pointer + " " + this);
         }
-        if (!mQueue.contains(tracker)) {
-            return;
-        }
-        final Iterator<ElementActions> it = mQueue.iterator();
-        while (it.hasNext()) {
-            final ElementActions t = it.next();
-            if (t == tracker) {
-                break;
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        int newSize, index;
+        for (newSize = index = 0; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
+            if (element == pointer) {
+                break; // Stop releasing elements.
             }
-            if (!t.isModifier()) {
-                t.onPhantomUpEvent(eventTime);
-                it.remove();
+            if (!element.isModifier()) {
+                element.onPhantomUpEvent(eventTime);
+                continue; // Remove this element from the expandableArray.
+            }
+            if (newSize != index) {
+                // Shift this element toward the beginning of the expandableArray.
+                expandableArray.set(newSize, element);
+            }
+            newSize++;
+        }
+        // Shift rest of the expandableArray.
+        int count = 0;
+        for (; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
+            if (element == pointer) {
+                if (count > 0) {
+                    Log.w(TAG, "Found duplicated element in releaseAllPointersOlderThan: "
+                            + pointer);
+                }
+                count++;
+            }
+            if (newSize != index) {
+                expandableArray.set(newSize, expandableArray.get(index));
+                newSize++;
             }
         }
+        mArraySize = newSize;
     }
 
-    public void releaseAllPointers(long eventTime) {
+    public void releaseAllPointers(final long eventTime) {
         releaseAllPointersExcept(null, eventTime);
     }
 
-    public synchronized void releaseAllPointersExcept(ElementActions tracker, long eventTime) {
+    public synchronized void releaseAllPointersExcept(final Element pointer,
+            final long eventTime) {
         if (DEBUG) {
-            if (tracker == null) {
+            if (pointer == null) {
                 Log.d(TAG, "releaseAllPoniters: " + this);
             } else {
-                Log.d(TAG, "releaseAllPoniterExcept: " + tracker + " " + this);
+                Log.d(TAG, "releaseAllPoniterExcept: " + pointer + " " + this);
             }
         }
-        final Iterator<ElementActions> it = mQueue.iterator();
-        while (it.hasNext()) {
-            final ElementActions t = it.next();
-            if (t != tracker) {
-                t.onPhantomUpEvent(eventTime);
-                it.remove();
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        int newSize = 0, count = 0;
+        for (int index = 0; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
+            if (element == pointer) {
+                if (count > 0) {
+                    Log.w(TAG, "Found duplicated element in releaseAllPointersExcept: " + pointer);
+                }
+                count++;
+            } else {
+                element.onPhantomUpEvent(eventTime);
+                continue; // Remove this element from the expandableArray.
             }
+            if (newSize != index) {
+                // Shift this element toward the beginning of the expandableArray.
+                expandableArray.set(newSize, element);
+            }
+            newSize++;
         }
+        mArraySize = newSize;
     }
 
-    public synchronized boolean hasModifierKeyOlderThan(ElementActions tracker) {
-        final Iterator<ElementActions> it = mQueue.iterator();
-        while (it.hasNext()) {
-            final ElementActions t = it.next();
-            if (t == tracker) {
-                break;
+    public synchronized boolean hasModifierKeyOlderThan(final Element pointer) {
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        for (int index = 0; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
+            if (element == pointer) {
+                return false; // Stop searching modifier key.
             }
-            if (t.isModifier()) {
+            if (element.isModifier()) {
                 return true;
             }
         }
@@ -104,8 +165,11 @@
     }
 
     public synchronized boolean isAnyInSlidingKeyInput() {
-        for (final ElementActions tracker : mQueue) {
-            if (tracker.isInSlidingKeyInput()) {
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        for (int index = 0; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
+            if (element.isInSlidingKeyInput()) {
                 return true;
             }
         }
@@ -113,12 +177,15 @@
     }
 
     @Override
-    public String toString() {
+    public synchronized String toString() {
         final StringBuilder sb = new StringBuilder();
-        for (final ElementActions tracker : mQueue) {
+        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
+        final int arraySize = mArraySize;
+        for (int index = 0; index < arraySize; index++) {
+            final Element element = expandableArray.get(index);
             if (sb.length() > 0)
                 sb.append(" ");
-            sb.append(tracker.toString());
+            sb.append(element.toString());
         }
         return "[" + sb.toString() + "]";
     }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 4550860..43901ba 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -517,7 +517,7 @@
 
     /* package private */ void resetSuggestMainDict() {
         final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
-        mSuggest.resetMainDict(this, subtypeLocale);
+        mSuggest.resetMainDict(this, subtypeLocale, this /* SuggestInitializationListener */);
         mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 5e2a041..a65d36a 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -60,13 +60,11 @@
 
     // Locale used for upper- and title-casing words
     private final Locale mLocale;
-    private final SuggestInitializationListener mListener;
 
     public Suggest(final Context context, final Locale locale,
             final SuggestInitializationListener listener) {
-        initAsynchronously(context, locale);
+        initAsynchronously(context, locale, listener);
         mLocale = locale;
-        mListener = listener;
     }
 
     /* package for test */ Suggest(final Context context, final File dictionary,
@@ -74,7 +72,6 @@
         final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
                 startOffset, length /* useFullEditDistance */, false, locale);
         mLocale = locale;
-        mListener = null;
         mMainDictionary = mainDict;
         addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, mainDict);
         initWhitelistAndAutocorrectAndPool(context, locale);
@@ -85,8 +82,9 @@
         addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_WHITELIST, mWhiteListDictionary);
     }
 
-    private void initAsynchronously(final Context context, final Locale locale) {
-        resetMainDict(context, locale);
+    private void initAsynchronously(final Context context, final Locale locale,
+            final SuggestInitializationListener listener) {
+        resetMainDict(context, locale, listener);
 
         // TODO: read the whitelist and init the pool asynchronously too.
         // initPool should be done asynchronously now that the pool is thread-safe.
@@ -104,10 +102,11 @@
         }
     }
 
-    public void resetMainDict(final Context context, final Locale locale) {
+    public void resetMainDict(final Context context, final Locale locale,
+            final SuggestInitializationListener listener) {
         mMainDictionary = null;
-        if (mListener != null) {
-            mListener.onUpdateMainDictionaryAvailability(hasMainDictionary());
+        if (listener != null) {
+            listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
         }
         new Thread("InitializeBinaryDictionary") {
             @Override
@@ -116,8 +115,8 @@
                         DictionaryFactory.createMainDictionaryFromManager(context, locale);
                 addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, newMainDict);
                 mMainDictionary = newMainDict;
-                if (mListener != null) {
-                    mListener.onUpdateMainDictionaryAvailability(hasMainDictionary());
+                if (listener != null) {
+                    listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
                 }
             }
         }.start();
diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
index 74390cc..a01ac37 100644
--- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
+++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "LatinIME: jni: ProximityInfo"
 
-#include <string>
-
 #include "com_android_inputmethod_keyboard_ProximityInfo.h"
 #include "jni.h"
 #include "jni_common.h"
@@ -26,45 +24,22 @@
 namespace latinime {
 
 static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object,
-        jstring localejStr, jint maxProximityCharsSize, jint displayWidth, jint displayHeight,
-        jint gridWidth, jint gridHeight, jint mostCommonkeyWidth, jintArray proximityCharsArray,
-        jint keyCount, jintArray keyXCoordinateArray, jintArray keyYCoordinateArray,
-        jintArray keyWidthArray, jintArray keyHeightArray, jintArray keyCharCodeArray,
-        jfloatArray sweetSpotCenterXArray, jfloatArray sweetSpotCenterYArray,
-        jfloatArray sweetSpotRadiusArray) {
-    const char *localeStrPtr = env->GetStringUTFChars(localejStr, 0);
-    const std::string localeStr(localeStrPtr);
-    jint *proximityChars = env->GetIntArrayElements(proximityCharsArray, 0);
-    jint *keyXCoordinates = safeGetIntArrayElements(env, keyXCoordinateArray);
-    jint *keyYCoordinates = safeGetIntArrayElements(env, keyYCoordinateArray);
-    jint *keyWidths = safeGetIntArrayElements(env, keyWidthArray);
-    jint *keyHeights = safeGetIntArrayElements(env, keyHeightArray);
-    jint *keyCharCodes = safeGetIntArrayElements(env, keyCharCodeArray);
-    jfloat *sweetSpotCenterXs = safeGetFloatArrayElements(env, sweetSpotCenterXArray);
-    jfloat *sweetSpotCenterYs = safeGetFloatArrayElements(env, sweetSpotCenterYArray);
-    jfloat *sweetSpotRadii = safeGetFloatArrayElements(env, sweetSpotRadiusArray);
-    ProximityInfo *proximityInfo = new ProximityInfo(
-            localeStr, maxProximityCharsSize, displayWidth, displayHeight, gridWidth, gridHeight,
-            mostCommonkeyWidth, (const int32_t*)proximityChars, keyCount,
-            (const int32_t*)keyXCoordinates, (const int32_t*)keyYCoordinates,
-            (const int32_t*)keyWidths, (const int32_t*)keyHeights, (const int32_t*)keyCharCodes,
-            (const float*)sweetSpotCenterXs, (const float*)sweetSpotCenterYs,
-            (const float*)sweetSpotRadii);
-    safeReleaseFloatArrayElements(env, sweetSpotRadiusArray, sweetSpotRadii);
-    safeReleaseFloatArrayElements(env, sweetSpotCenterYArray, sweetSpotCenterYs);
-    safeReleaseFloatArrayElements(env, sweetSpotCenterXArray, sweetSpotCenterXs);
-    safeReleaseIntArrayElements(env, keyCharCodeArray, keyCharCodes);
-    safeReleaseIntArrayElements(env, keyHeightArray, keyHeights);
-    safeReleaseIntArrayElements(env, keyWidthArray, keyWidths);
-    safeReleaseIntArrayElements(env, keyYCoordinateArray, keyYCoordinates);
-    safeReleaseIntArrayElements(env, keyXCoordinateArray, keyXCoordinates);
-    env->ReleaseIntArrayElements(proximityCharsArray, proximityChars, 0);
-    env->ReleaseStringUTFChars(localejStr, localeStrPtr);
-    return (jlong)proximityInfo;
+        jstring localeJStr, jint maxProximityCharsSize, jint displayWidth, jint displayHeight,
+        jint gridWidth, jint gridHeight, jint mostCommonkeyWidth, jintArray proximityChars,
+        jint keyCount, jintArray keyXCoordinates, jintArray keyYCoordinates,
+        jintArray keyWidths, jintArray keyHeights, jintArray keyCharCodes,
+        jfloatArray sweetSpotCenterXs, jfloatArray sweetSpotCenterYs, jfloatArray sweetSpotRadii) {
+    const char *localeCStr = env->GetStringUTFChars(localeJStr, 0);
+    ProximityInfo *proximityInfo = new ProximityInfo(env, localeCStr, maxProximityCharsSize,
+            displayWidth, displayHeight, gridWidth, gridHeight, mostCommonkeyWidth, proximityChars,
+            keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
+            sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+    env->ReleaseStringUTFChars(localeJStr, localeCStr);
+    return reinterpret_cast<jlong>(proximityInfo);
 }
 
 static void latinime_Keyboard_release(JNIEnv *env, jobject object, jlong proximityInfo) {
-    ProximityInfo *pi = (ProximityInfo*)proximityInfo;
+    ProximityInfo *pi = reinterpret_cast<ProximityInfo*>(proximityInfo);
     if (!pi) return;
     delete pi;
 }
diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp
index dde5f64..795262a 100644
--- a/native/jni/jni_common.cpp
+++ b/native/jni/jni_common.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "LatinIME: jni"
 
+#include <cassert>
+
 #include "com_android_inputmethod_keyboard_ProximityInfo.h"
 #include "com_android_inputmethod_latin_BinaryDictionary.h"
 #include "com_android_inputmethod_latin_DicTraverseSession.h"
@@ -24,8 +26,6 @@
 #include "jni.h"
 #include "jni_common.h"
 
-#include <cassert>
-
 using namespace latinime;
 
 /*
diff --git a/native/jni/jni_common.h b/native/jni/jni_common.h
index 658ff18..993f97e 100644
--- a/native/jni/jni_common.h
+++ b/native/jni/jni_common.h
@@ -24,32 +24,5 @@
 int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods,
         int numMethods);
 
-inline jint *safeGetIntArrayElements(JNIEnv *env, jintArray jArray) {
-    if (jArray) {
-        return env->GetIntArrayElements(jArray, 0);
-    } else {
-        return 0;
-    }
-}
-
-inline jfloat *safeGetFloatArrayElements(JNIEnv *env, jfloatArray jArray) {
-    if (jArray) {
-        return env->GetFloatArrayElements(jArray, 0);
-    } else {
-        return 0;
-    }
-}
-
-inline void safeReleaseIntArrayElements(JNIEnv *env, jintArray jArray, jint *cArray) {
-    if (jArray) {
-        env->ReleaseIntArrayElements(jArray, cArray, 0);
-    }
-}
-
-inline void safeReleaseFloatArrayElements(JNIEnv *env, jfloatArray jArray, jfloat *cArray) {
-    if (jArray) {
-        env->ReleaseFloatArrayElements(jArray, cArray, 0);
-    }
-}
 } // namespace latinime
 #endif // LATINIME_JNI_COMMON_H
diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp
index cee408d..7bae413 100644
--- a/native/jni/src/proximity_info.cpp
+++ b/native/jni/src/proximity_info.cpp
@@ -24,25 +24,36 @@
 #include "additional_proximity_chars.h"
 #include "char_utils.h"
 #include "defines.h"
+#include "jni.h"
 #include "proximity_info.h"
 
 namespace latinime {
 
-inline void copyOrFillZero(void *to, const void *from, size_t size) {
-    if (from) {
-        memcpy(to, from, size);
-    } else {
-        memset(to, 0, size);
+static inline void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray, jsize len,
+        jint *buffer) {
+    if (jArray && buffer) {
+        env->GetIntArrayRegion(jArray, 0, len, buffer);
+    } else if (buffer) {
+        memset(buffer, 0, len);
     }
 }
 
-ProximityInfo::ProximityInfo(const std::string localeStr, const int maxProximityCharsSize,
+static inline void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray, jsize len,
+        jfloat *buffer) {
+    if (jArray && buffer) {
+        env->GetFloatArrayRegion(jArray, 0, len, buffer);
+    } else if (buffer) {
+        memset(buffer, 0, len);
+    }
+}
+
+ProximityInfo::ProximityInfo(JNIEnv *env, const char *localeCStr, const int maxProximityCharsSize,
         const int keyboardWidth, const int keyboardHeight, const int gridWidth,
-        const int gridHeight, const int mostCommonKeyWidth,
-        const int32_t *proximityCharsArray, const int keyCount, const int32_t *keyXCoordinates,
-        const int32_t *keyYCoordinates, const int32_t *keyWidths, const int32_t *keyHeights,
-        const int32_t *keyCharCodes, const float *sweetSpotCenterXs, const float *sweetSpotCenterYs,
-        const float *sweetSpotRadii)
+        const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars,
+        const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates,
+        const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes,
+        const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs,
+        const jfloatArray sweetSpotRadii)
         : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), KEYBOARD_WIDTH(keyboardWidth),
           KEYBOARD_HEIGHT(keyboardHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight),
           MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
@@ -52,26 +63,21 @@
           HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
                   && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
                   && sweetSpotCenterYs && sweetSpotRadii),
-          mLocaleStr(localeStr) {
+          mLocaleStr(localeCStr) {
     const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
     if (DEBUG_PROXIMITY_INFO) {
         AKLOGI("Create proximity info array %d", proximityGridLength);
     }
     mProximityCharsArray = new int32_t[proximityGridLength];
-    memcpy(mProximityCharsArray, proximityCharsArray,
-            proximityGridLength * sizeof(mProximityCharsArray[0]));
-
-    copyOrFillZero(mKeyXCoordinates, keyXCoordinates, KEY_COUNT * sizeof(mKeyXCoordinates[0]));
-    copyOrFillZero(mKeyYCoordinates, keyYCoordinates, KEY_COUNT * sizeof(mKeyYCoordinates[0]));
-    copyOrFillZero(mKeyWidths, keyWidths, KEY_COUNT * sizeof(mKeyWidths[0]));
-    copyOrFillZero(mKeyHeights, keyHeights, KEY_COUNT * sizeof(mKeyHeights[0]));
-    copyOrFillZero(mKeyCharCodes, keyCharCodes, KEY_COUNT * sizeof(mKeyCharCodes[0]));
-    copyOrFillZero(mSweetSpotCenterXs, sweetSpotCenterXs,
-            KEY_COUNT * sizeof(mSweetSpotCenterXs[0]));
-    copyOrFillZero(mSweetSpotCenterYs, sweetSpotCenterYs,
-            KEY_COUNT * sizeof(mSweetSpotCenterYs[0]));
-    copyOrFillZero(mSweetSpotRadii, sweetSpotRadii, KEY_COUNT * sizeof(mSweetSpotRadii[0]));
-
+    safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityGridLength, mProximityCharsArray);
+    safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
+    safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
+    safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths);
+    safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights);
+    safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCharCodes);
+    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs);
+    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs);
+    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
     initializeCodeToKeyIndex();
 }
 
diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h
index abd07dd..5dd378d 100644
--- a/native/jni/src/proximity_info.h
+++ b/native/jni/src/proximity_info.h
@@ -21,6 +21,7 @@
 #include <string>
 
 #include "defines.h"
+#include "jni.h"
 
 namespace latinime {
 
@@ -28,13 +29,13 @@
 
 class ProximityInfo {
  public:
-    ProximityInfo(const std::string localeStr, const int maxProximityCharsSize,
+    ProximityInfo(JNIEnv *env, const char *localeCStr, const int maxProximityCharsSize,
             const int keyboardWidth, const int keyboardHeight, const int gridWidth,
-            const int gridHeight, const int mostCommonkeyWidth,
-            const int32_t *proximityCharsArray, const int keyCount, const int32_t *keyXCoordinates,
-            const int32_t *keyYCoordinates, const int32_t *keyWidths, const int32_t *keyHeights,
-            const int32_t *keyCharCodes, const float *sweetSpotCenterXs,
-            const float *sweetSpotCenterYs, const float *sweetSpotRadii);
+            const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars,
+            const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates,
+            const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes,
+            const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs,
+            const jfloatArray sweetSpotRadii);
     ~ProximityInfo();
     bool hasSpaceProximity(const int x, const int y) const;
     int getNormalizedSquaredDistance(const int inputIndex, const int proximityIndex) const;
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
index 99fbc96..8fed28f 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
@@ -19,7 +19,7 @@
 import android.test.AndroidTestCase;
 
 public class PointerTrackerQueueTests extends AndroidTestCase {
-    public static class Element implements PointerTrackerQueue.ElementActions {
+    public static class Element implements PointerTrackerQueue.Element {
         public static int sPhantomUpCount;
         public static final long NOT_HAPPENED = -1;
 
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index e9c11ac..df8cb10 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -24,7 +24,7 @@
         $(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \
         $(call all-java-files-under,tests)
 LOCAL_JAR_MANIFEST := etc/manifest.txt
-LOCAL_MODULE := dicttool
+LOCAL_MODULE := dicttool_aosp
 LOCAL_JAVA_LIBRARIES := junit
 LOCAL_MODULE_TAGS := eng
 
diff --git a/tools/dicttool/etc/Android.mk b/tools/dicttool/etc/Android.mk
index 1eab70f..8952827 100644
--- a/tools/dicttool/etc/Android.mk
+++ b/tools/dicttool/etc/Android.mk
@@ -16,5 +16,5 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := eng
-LOCAL_PREBUILT_EXECUTABLES := dicttool makedict
+LOCAL_PREBUILT_EXECUTABLES := dicttool_aosp makedict_aosp
 include $(BUILD_HOST_PREBUILT)
diff --git a/tools/dicttool/etc/dicttool b/tools/dicttool/etc/dicttool_aosp
similarity index 98%
rename from tools/dicttool/etc/dicttool
rename to tools/dicttool/etc/dicttool_aosp
index 8a39694..a4879a2 100755
--- a/tools/dicttool/etc/dicttool
+++ b/tools/dicttool/etc/dicttool_aosp
@@ -33,7 +33,7 @@
 prog="${progdir}"/`basename "${prog}"`
 cd "${oldwd}"
 
-jarfile=dicttool.jar
+jarfile=dicttool_aosp.jar
 frameworkdir="$progdir"
 if [ ! -r "$frameworkdir/$jarfile" ]
 then
diff --git a/tools/dicttool/etc/makedict b/tools/dicttool/etc/makedict_aosp
similarity index 96%
rename from tools/dicttool/etc/makedict
rename to tools/dicttool/etc/makedict_aosp
index fffeb23..095c505 100755
--- a/tools/dicttool/etc/makedict
+++ b/tools/dicttool/etc/makedict_aosp
@@ -15,4 +15,4 @@
 
 # Dicttool supports making the dictionary using the 'makedict' command and
 # the same arguments that the old 'makedict' command used to accept.
-dicttool makedict $@
+dicttool_aosp makedict $@
diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/AdditionalCommandList.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/AdditionalCommandList.java
new file mode 100644
index 0000000..8d4eb75
--- /dev/null
+++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/AdditionalCommandList.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin.dicttool;
+
+public class AdditionalCommandList {
+    public static void populate() {
+    }
+}
diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/CommandList.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/CommandList.java
new file mode 100644
index 0000000..d16b069
--- /dev/null
+++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/CommandList.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin.dicttool;
+
+public class CommandList {
+    public static void populate() {
+        Dicttool.addCommand("info", Info.class);
+        Dicttool.addCommand("compress", Compress.Compressor.class);
+        Dicttool.addCommand("uncompress", Compress.Uncompressor.class);
+        Dicttool.addCommand("makedict", Makedict.class);
+    }
+}
diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java
index c14ce7b..bf417fb 100644
--- a/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java
+++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/Dicttool.java
@@ -32,10 +32,11 @@
     static HashMap<String, Class<? extends Command>> sCommands =
             new HashMap<String, Class<? extends Command>>();
     static {
-        sCommands.put("info", Info.class);
-        sCommands.put("compress", Compress.Compressor.class);
-        sCommands.put("uncompress", Compress.Uncompressor.class);
-        sCommands.put("makedict", Makedict.class);
+        CommandList.populate();
+        AdditionalCommandList.populate();
+    }
+    public static void addCommand(final String commandName, final Class<? extends Command> cls) {
+        sCommands.put(commandName, cls);
     }
 
     private static Command getCommandInstance(final String commandName) {