Merge "Import translations. DO NOT MERGE"
diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png
index d75fcac..d85663b 100644
--- a/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png
+++ b/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space.png b/java/res/drawable-hdpi/sym_keyboard_space.png
index 780733e..78cd6b7 100644
--- a/java/res/drawable-hdpi/sym_keyboard_space.png
+++ b/java/res/drawable-hdpi/sym_keyboard_space.png
Binary files differ
diff --git a/java/res/drawable-mdpi/more_keys_divider.png b/java/res/drawable-mdpi/more_keys_divider.png
index a46284f..0f71c61 100644
--- a/java/res/drawable-mdpi/more_keys_divider.png
+++ b/java/res/drawable-mdpi/more_keys_divider.png
Binary files differ
diff --git a/java/res/drawable-mdpi/more_suggestions_divider.png b/java/res/drawable-mdpi/more_suggestions_divider.png
index a46284f..0f71c61 100644
--- a/java/res/drawable-mdpi/more_suggestions_divider.png
+++ b/java/res/drawable-mdpi/more_suggestions_divider.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png
index a10dc8f..fee1580 100644
--- a/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png
+++ b/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space.png b/java/res/drawable-mdpi/sym_keyboard_space.png
index cbe4a88..6d03e63 100644
--- a/java/res/drawable-mdpi/sym_keyboard_space.png
+++ b/java/res/drawable-mdpi/sym_keyboard_space.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png
index 0650e01..b0ee35d 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space.png b/java/res/drawable-xhdpi/sym_keyboard_space.png
index 66fc3e9..3691280 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_space.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_space.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png
index 2079e04..3ab7900 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png
index c4178d9..99543a1 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png
index d3d8733..e9e3792 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png
index d7ec8bc..6c1143a 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png
Binary files differ
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index 7fff46a..7e21667 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -632,7 +632,9 @@
     }
 
     public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
-        // TODO:
+        if (!enabled) return;
+        // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
+        setLayerType(LAYER_TYPE_HARDWARE, null);
     }
 
     private static void setupAlphabetKey(final TextView alphabetKey, final String label,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 044cd11..56acdde 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -31,7 +31,7 @@
 
 public final class KeyboardTextsSet {
     public static final String PREFIX_TEXT = "!text/";
-    public static final String SWITCH_TO_ALPHA_KEY_LABEL = "label_to_alpha_key";
+    public static final String SWITCH_TO_ALPHA_KEY_LABEL = "keylabel_to_alpha";
 
     private static final char BACKSLASH = Constants.CODE_BACKSLASH;
     private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index 8b8d577..ae2d7c9 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -480,6 +480,9 @@
             return false;
         }
         final Dictionaries dictionaries = mDictionaries;
+        if (dictionaries.mLocale == null) {
+            return false;
+        }
         final String lowerCasedWord = word.toLowerCase(dictionaries.mLocale);
         final Map<String, Dictionary> dictMap = dictionaries.mDictMap;
         for (final Dictionary dictionary : dictMap.values()) {
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index 07217e4..f255034 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -18,9 +18,7 @@
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory;
 
-import java.io.File;
 import java.util.Date;
 import java.util.HashMap;
 
@@ -363,42 +361,6 @@
         }
     }
 
-    /**
-     * Returns new dictionary decoder.
-     *
-     * @param dictFile the dictionary file.
-     * @param offset the offset in the file.
-     * @param length the length of the file, in bytes.
-     * @param bufferType The type of buffer, as one of USE_* in DictDecoder.
-     * @return new dictionary decoder if the dictionary file exists, otherwise null.
-     */
-    public static DictDecoder getDictDecoder(final File dictFile, final long offset,
-            final long length, final int bufferType) {
-        if (dictFile.isDirectory()) {
-            return new Ver4DictDecoder(dictFile, bufferType);
-        } else if (dictFile.isFile()) {
-            return new Ver2DictDecoder(dictFile, offset, length, bufferType);
-        }
-        return null;
-    }
-
-    @UsedForTesting
-    public static DictDecoder getDictDecoder(final File dictFile, final long offset,
-            final long length, final DictionaryBufferFactory factory) {
-        if (dictFile.isDirectory()) {
-            return new Ver4DictDecoder(dictFile, factory);
-        } else if (dictFile.isFile()) {
-            return new Ver2DictDecoder(dictFile, offset, length, factory);
-        }
-        return null;
-    }
-
-    @UsedForTesting
-    public static DictDecoder getDictDecoder(final File dictFile, final long offset,
-            final long length) {
-        return getDictDecoder(dictFile, offset, length, DictDecoder.USE_READONLY_BYTEBUFFER);
-    }
-
     private FormatSpec() {
         // This utility class is not publicly instantiable.
     }
diff --git a/java/src/com/android/inputmethod/latin/makedict/MakedictLog.java b/java/src/com/android/inputmethod/latin/makedict/MakedictLog.java
deleted file mode 100644
index cf07209..0000000
--- a/java/src/com/android/inputmethod/latin/makedict/MakedictLog.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2011 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.makedict;
-
-import android.util.Log;
-
-/**
- * Wrapper to redirect log events to the right output medium.
- */
-public final class MakedictLog {
-    public static final boolean DBG = false;
-    private static final String TAG = MakedictLog.class.getSimpleName();
-
-    public static void d(String message) {
-        if (DBG) {
-            Log.d(TAG, message);
-        }
-    }
-
-    public static void i(String message) {
-        if (DBG) {
-            Log.i(TAG, message);
-        }
-    }
-
-    public static void w(String message) {
-        Log.w(TAG, message);
-    }
-
-    public static void e(String message) {
-        Log.e(TAG, message);
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index e531d4b..315913e 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -23,12 +23,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.AssetFileAddress;
 import com.android.inputmethod.latin.BinaryDictionaryGetter;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.DictionaryHeader;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
 import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index ac0b4ab..154ea98 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -199,47 +199,30 @@
         ASSERT(false);
         return;
     }
-    int outputCodePoints[outputCodePointsLength];
-    int scores[scoresLength];
-    const jsize spaceIndicesLength = env->GetArrayLength(outSpaceIndicesArray);
-    int spaceIndices[spaceIndicesLength];
-    const jsize outputTypesLength = env->GetArrayLength(outTypesArray);
-    int outputTypes[outputTypesLength];
     const jsize outputAutoCommitFirstWordConfidenceLength =
             env->GetArrayLength(outAutoCommitFirstWordConfidenceArray);
-    // We only use the first result, as obviously we will only ever autocommit the first one
     ASSERT(outputAutoCommitFirstWordConfidenceLength == 1);
-    int outputAutoCommitFirstWordConfidence[outputAutoCommitFirstWordConfidenceLength];
-    memset(outputCodePoints, 0, sizeof(outputCodePoints));
-    memset(scores, 0, sizeof(scores));
-    memset(spaceIndices, 0, sizeof(spaceIndices));
-    memset(outputTypes, 0, sizeof(outputTypes));
-    memset(outputAutoCommitFirstWordConfidence, 0, sizeof(outputAutoCommitFirstWordConfidence));
-
-    if (givenSuggestOptions.isGesture() || inputSize > 0) {
-        // TODO: Use SuggestionResults to return suggestions.
-        count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
-                times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints,
-                prevWordCodePointsLength, &givenSuggestOptions, outputCodePoints,
-                scores, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence);
-    } else {
-        SuggestionResults suggestionResults(MAX_RESULTS);
-        dictionary->getPredictions(prevWordCodePoints, prevWordCodePointsLength,
-                &suggestionResults);
-        suggestionResults.outputSuggestions(env, outSuggestionCount, outCodePointsArray,
-                outScoresArray, outSpaceIndicesArray, outTypesArray,
-                outAutoCommitFirstWordConfidenceArray);
+    if (outputAutoCommitFirstWordConfidenceLength != 1) {
+        // We only use the first result, as obviously we will only ever autocommit the first one
+        AKLOGE("Invalid outputAutoCommitFirstWordConfidenceLength: %d",
+                outputAutoCommitFirstWordConfidenceLength);
+        ASSERT(false);
         return;
     }
 
-    // Copy back the output values
-    env->SetIntArrayRegion(outSuggestionCount, 0, 1 /* len */, &count);
-    env->SetIntArrayRegion(outCodePointsArray, 0, outputCodePointsLength, outputCodePoints);
-    env->SetIntArrayRegion(outScoresArray, 0, scoresLength, scores);
-    env->SetIntArrayRegion(outSpaceIndicesArray, 0, spaceIndicesLength, spaceIndices);
-    env->SetIntArrayRegion(outTypesArray, 0, outputTypesLength, outputTypes);
-    env->SetIntArrayRegion(outAutoCommitFirstWordConfidenceArray, 0,
-            outputAutoCommitFirstWordConfidenceLength, outputAutoCommitFirstWordConfidence);
+    SuggestionResults suggestionResults(MAX_RESULTS);
+    if (givenSuggestOptions.isGesture() || inputSize > 0) {
+        // TODO: Use SuggestionResults to return suggestions.
+        dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
+                times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints,
+                prevWordCodePointsLength, &givenSuggestOptions, &suggestionResults);
+    } else {
+        dictionary->getPredictions(prevWordCodePoints, prevWordCodePointsLength,
+                &suggestionResults);
+    }
+    suggestionResults.outputSuggestions(env, outSuggestionCount, outCodePointsArray,
+            outScoresArray, outSpaceIndicesArray, outTypesArray,
+            outAutoCommitFirstWordConfidenceArray);
 }
 
 static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz, jlong dict,
diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp
index 9fa7ef8..ce5e30c 100644
--- a/native/jni/jni_common.cpp
+++ b/native/jni/jni_common.cpp
@@ -67,7 +67,7 @@
         AKLOGE("Native registration unable to find class '%s'", className);
         return JNI_FALSE;
     }
-    if (env->RegisterNatives(clazz, methods, numMethods) < 0) {
+    if (env->RegisterNatives(clazz, methods, numMethods) != 0) {
         AKLOGE("RegisterNatives failed for '%s'", className);
         env->DeleteLocalRef(clazz);
         return JNI_FALSE;
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 4e6ff95..3651cd5 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -103,7 +103,8 @@
 #define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__)
 #endif // defined(HOST_TOOL)
 
-#define DUMP_RESULT(words, frequencies) do { dumpResult(words, frequencies); } while (0)
+#define DUMP_SUGGESTION(words, frequencies, index, score) \
+        do { dumpWordInfo(words, frequencies, index, score); } while (0)
 #define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0)
 #define INTS_TO_CHARS(input, length, output, outlength) do { \
         intArrayToCharArray(input, length, output, outlength); } while (0)
@@ -165,7 +166,7 @@
 #else // defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
 #define AKLOGE(fmt, ...)
 #define AKLOGI(fmt, ...)
-#define DUMP_RESULT(words, frequencies)
+#define DUMP_SUGGESTION(words, frequencies, index, score)
 #define DUMP_WORD(word, length)
 #undef DO_ASSERT_TEST
 #define ASSERT(success)
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 865aab6..3118cdf 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -218,10 +218,6 @@
         return CharUtils::isAsciiUpper(c);
     }
 
-    bool isFirstWord() const {
-        return mDicNodeProperties.getPrevWordTerminalPtNodePos() == NOT_A_DICT_POS;
-    }
-
     bool isCompletion(const int inputSize) const {
         return mDicNodeState.mDicNodeStateInput.getInputIndex(0) >= inputSize;
     }
@@ -292,7 +288,9 @@
     // the one that corresponds to the last word of the suggestion, and all the previous words
     // are concatenated together in mDicNodeStateOutput.
     int getTotalNodeSpaceCount() const {
-        if (isFirstWord()) return 0;
+        if (!hasMultipleWords()) {
+            return 0;
+        }
         return CharUtils::getSpaceCount(mDicNodeState.mDicNodeStateOutput.getCodePointBuf(),
                 mDicNodeState.mDicNodeStateOutput.getPrevWordsLength());
     }
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
index 48752f2..2d02a7d 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
@@ -16,8 +16,6 @@
 
 #include "suggest/core/dicnode/dic_node_utils.h"
 
-#include <cstring>
-
 #include "suggest/core/dicnode/dic_node.h"
 #include "suggest/core/dicnode/dic_node_vector.h"
 #include "suggest/core/dictionary/multi_bigram_map.h"
@@ -103,34 +101,4 @@
             NOT_A_PROBABILITY);
 }
 
-////////////////
-// Char utils //
-////////////////
-
-// TODO: Move to char_utils?
-/* static */ int DicNodeUtils::appendTwoWords(const int *const src0, const int16_t length0,
-        const int *const src1, const int16_t length1, int *const dest) {
-    int actualLength0 = 0;
-    for (int i = 0; i < length0; ++i) {
-        if (src0[i] == 0) {
-            break;
-        }
-        actualLength0 = i + 1;
-    }
-    actualLength0 = std::min(actualLength0, MAX_WORD_LENGTH);
-    memmove(dest, src0, actualLength0 * sizeof(dest[0]));
-    if (!src1 || length1 == 0) {
-        return actualLength0;
-    }
-    int actualLength1 = 0;
-    for (int i = 0; i < length1; ++i) {
-        if (src1[i] == 0) {
-            break;
-        }
-        actualLength1 = i + 1;
-    }
-    actualLength1 = std::min(actualLength1, MAX_WORD_LENGTH - actualLength0);
-    memmove(&dest[actualLength0], src1, actualLength1 * sizeof(dest[0]));
-    return actualLength0 + actualLength1;
-}
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.h b/native/jni/src/suggest/core/dicnode/dic_node_utils.h
index 3f1514a..4c0f1f1 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.h
@@ -17,8 +17,6 @@
 #ifndef LATINIME_DIC_NODE_UTILS_H
 #define LATINIME_DIC_NODE_UTILS_H
 
-#include <stdint.h>
-
 #include "defines.h"
 
 namespace latinime {
@@ -30,8 +28,6 @@
 
 class DicNodeUtils {
  public:
-    static int appendTwoWords(const int *src0, const int16_t length0, const int *src1,
-            const int16_t length1, int *const dest);
     static void initAsRoot(
             const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
             const int prevWordPtNodePos, DicNode *const newRootDicNode);
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 07b07f7..ae4646d 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -22,6 +22,7 @@
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_header_structure_policy.h"
+#include "suggest/core/result/suggestion_results.h"
 #include "suggest/core/session/dic_traverse_session.h"
 #include "suggest/core/suggest.h"
 #include "suggest/core/suggest_options.h"
@@ -43,34 +44,25 @@
     logDictionaryInfo(env);
 }
 
-int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
+void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
         int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
         int inputSize, int *prevWordCodePoints, int prevWordLength,
-        const SuggestOptions *const suggestOptions, int *outWords, int *outputScores,
-        int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const {
+        const SuggestOptions *const suggestOptions,
+        SuggestionResults *const outSuggestionResults) const {
     TimeKeeper::setCurrentTime();
-    int result = 0;
+    DicTraverseSession::initSessionInstance(
+            traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
     if (suggestOptions->isGesture()) {
-        DicTraverseSession::initSessionInstance(
-                traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
-        result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
-                ycoordinates, times, pointerIds, inputCodePoints, inputSize, outWords,
-                outputScores, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence);
-        if (DEBUG_DICT) {
-            DUMP_RESULT(outWords, outputScores);
-        }
-        return result;
-    } else {
-        DicTraverseSession::initSessionInstance(
-                traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
-        result = mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
+        mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
                 ycoordinates, times, pointerIds, inputCodePoints, inputSize,
-                outWords, outputScores, spaceIndices, outputTypes,
-                outputAutoCommitFirstWordConfidence);
-        if (DEBUG_DICT) {
-            DUMP_RESULT(outWords, outputScores);
-        }
-        return result;
+                outSuggestionResults);
+    } else {
+        mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
+                ycoordinates, times, pointerIds, inputCodePoints, inputSize,
+                outSuggestionResults);
+    }
+    if (DEBUG_DICT) {
+        outSuggestionResults->dumpSuggestions();
     }
 }
 
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 4d482e7..df5fc9b 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -62,11 +62,11 @@
     Dictionary(JNIEnv *env, DictionaryStructureWithBufferPolicy::StructurePolicyPtr
             dictionaryStructureWithBufferPolicy);
 
-    int getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
+    void getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
             int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
             int inputSize, int *prevWordCodePoints, int prevWordLength,
-            const SuggestOptions *const suggestOptions, int *outWords, int *outputScores,
-            int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const;
+            const SuggestOptions *const suggestOptions,
+            SuggestionResults *const outSuggestionResults) const;
 
     void getPredictions(const int *word, int length,
             SuggestionResults *const outSuggestionResults) const;
diff --git a/native/jni/src/suggest/core/policy/scoring.h b/native/jni/src/suggest/core/policy/scoring.h
index 0251475..292194bf 100644
--- a/native/jni/src/suggest/core/policy/scoring.h
+++ b/native/jni/src/suggest/core/policy/scoring.h
@@ -23,6 +23,7 @@
 
 class DicNode;
 class DicTraverseSession;
+class SuggestionResults;
 
 // This class basically tweaks suggestions and distances apart from CompoundDistance
 class Scoring {
@@ -30,11 +31,8 @@
     virtual int calculateFinalScore(const float compoundDistance, const int inputSize,
             const ErrorTypeUtils::ErrorType containedErrorTypes, const bool forceCommit,
             const bool boostExactMatches) const = 0;
-    virtual bool getMostProbableString(const DicTraverseSession *const traverseSession,
-            const int terminalSize, const float languageWeight, int *const outputCodePoints,
-            int *const type, int *const freq) const = 0;
-    virtual void safetyNetForMostProbableString(const int scoreCount,
-            const int maxScore, int *const outputCodePoints, int *const scores) const = 0;
+    virtual void getMostProbableString(const DicTraverseSession *const traverseSession,
+            const float languageWeight, SuggestionResults *const outSuggestionResults) const = 0;
     virtual float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession,
             DicNode *const terminals, const int size) const = 0;
     virtual float getDoubleLetterDemotionDistanceCost(
diff --git a/native/jni/src/suggest/core/result/suggestion_results.cpp b/native/jni/src/suggest/core/result/suggestion_results.cpp
index 2be757d..da1c6bc 100644
--- a/native/jni/src/suggest/core/result/suggestion_results.cpp
+++ b/native/jni/src/suggest/core/result/suggestion_results.cpp
@@ -54,13 +54,23 @@
 
 void SuggestionResults::addPrediction(const int *const codePoints, const int codePointCount,
         const int probability) {
-    if (codePointCount <= 0 || codePointCount > MAX_WORD_LENGTH
-            || probability == NOT_A_PROBABILITY) {
+    if (probability == NOT_A_PROBABILITY) {
         // Invalid word.
         return;
     }
-    // Use probability as a score of the word.
-    const int score = probability;
+    addSuggestion(codePoints, codePointCount, probability, Dictionary::KIND_PREDICTION,
+            NOT_AN_INDEX, NOT_A_FIRST_WORD_CONFIDENCE);
+}
+
+void SuggestionResults::addSuggestion(const int *const codePoints, const int codePointCount,
+        const int score, const int type, const int indexToPartialCommit,
+        const int autocimmitFirstWordConfindence) {
+    if (codePointCount <= 0 || codePointCount > MAX_WORD_LENGTH) {
+        // Invalid word.
+        AKLOGE("Invalid word is added to the suggestion results. codePointCount: %d",
+                codePointCount);
+        return;
+    }
     if (getSuggestionCount() >= mMaxSuggestionCount) {
         const SuggestedWord &mWorstSuggestion = mSuggestedWords.top();
         if (score > mWorstSuggestion.getScore() || (score == mWorstSuggestion.getScore()
@@ -70,8 +80,31 @@
             return;
         }
     }
-    mSuggestedWords.push(SuggestedWord(codePoints, codePointCount, score,
-            Dictionary::KIND_PREDICTION, NOT_AN_INDEX, NOT_A_FIRST_WORD_CONFIDENCE));
+    mSuggestedWords.push(SuggestedWord(codePoints, codePointCount, score, type,
+            indexToPartialCommit, autocimmitFirstWordConfindence));
+}
+
+void SuggestionResults::getSortedScores(int *const outScores) const {
+    auto copyOfSuggestedWords = mSuggestedWords;
+    while (!copyOfSuggestedWords.empty()) {
+        const SuggestedWord &suggestedWord = copyOfSuggestedWords.top();
+        outScores[copyOfSuggestedWords.size() - 1] = suggestedWord.getScore();
+        copyOfSuggestedWords.pop();
+    }
+}
+
+void SuggestionResults::dumpSuggestions() const {
+    std::vector<SuggestedWord> suggestedWords;
+    auto copyOfSuggestedWords = mSuggestedWords;
+    while (!copyOfSuggestedWords.empty()) {
+        suggestedWords.push_back(copyOfSuggestedWords.top());
+        copyOfSuggestedWords.pop();
+    }
+    int index = 0;
+    for (auto it = suggestedWords.rbegin(); it != suggestedWords.rend(); ++it) {
+        DUMP_SUGGESTION(it->getCodePoint(), it->getCodePointCount(), index, it->getScore());
+        index++;
+    }
 }
 
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/result/suggestion_results.h b/native/jni/src/suggest/core/result/suggestion_results.h
index 0b841ca..020bab4 100644
--- a/native/jni/src/suggest/core/result/suggestion_results.h
+++ b/native/jni/src/suggest/core/result/suggestion_results.h
@@ -35,8 +35,12 @@
     void outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, jintArray outCodePointsArray,
             jintArray outScoresArray, jintArray outSpaceIndicesArray, jintArray outTypesArray,
             jintArray outAutoCommitFirstWordConfidenceArray);
-
     void addPrediction(const int *const codePoints, const int codePointCount, const int score);
+    void addSuggestion(const int *const codePoints, const int codePointCount,
+            const int score, const int type, const int indexToPartialCommit,
+            const int autocimmitFirstWordConfindence);
+    void getSortedScores(int *const outScores) const;
+    void dumpSuggestions() const;
 
     int getSuggestionCount() const {
         return mSuggestedWords.size();
diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
index 19912f2..b40f322 100644
--- a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
+++ b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
@@ -24,6 +24,7 @@
 #include "suggest/core/dictionary/dictionary.h"
 #include "suggest/core/dictionary/error_type_utils.h"
 #include "suggest/core/policy/scoring.h"
+#include "suggest/core/result/suggestion_results.h"
 #include "suggest/core/session/dic_traverse_session.h"
 
 namespace latinime {
@@ -31,10 +32,9 @@
 const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16;
 
 // TODO: Split this method.
-/* static */ int SuggestionsOutputUtils::outputSuggestions(
+/* static */ void SuggestionsOutputUtils::outputSuggestions(
         const Scoring *const scoringPolicy, DicTraverseSession *traverseSession,
-        int *outputScores, int *outputCodePoints, int *outputIndicesToPartialCommit,
-        int *outputTypes, int *outputAutoCommitFirstWordConfidence) {
+        SuggestionResults *const outSuggestionResults) {
 #if DEBUG_EVALUATE_MOST_PROBABLE_STRING
     const int terminalSize = 0;
 #else
@@ -49,18 +49,6 @@
 
     const float languageWeight = scoringPolicy->getAdjustedLanguageWeight(
             traverseSession, terminals, terminalSize);
-
-    int outputWordIndex = 0;
-    // Insert most probable word at index == 0 as long as there is one terminal at least
-    const bool hasMostProbableString =
-            scoringPolicy->getMostProbableString(traverseSession, terminalSize, languageWeight,
-                    &outputCodePoints[0], &outputTypes[0], &outputScores[0]);
-    if (hasMostProbableString) {
-        outputIndicesToPartialCommit[outputWordIndex] = NOT_AN_INDEX;
-        ++outputWordIndex;
-    }
-
-    int maxScore = S_INT_MIN;
     // Force autocorrection for obvious long multi-word suggestions when the top suggestion is
     // a long multiple words suggestion.
     // TODO: Implement a smarter auto-commit method for handling multi-word suggestions.
@@ -75,16 +63,12 @@
     // TODO: have partial commit work even with multiple pointers.
     const bool outputSecondWordFirstLetterInputIndex =
             traverseSession->isOnlyOnePointerUsed(0 /* pointerId */);
-    if (terminalSize > 0) {
-        // If we have no suggestions, don't write this
-        outputAutoCommitFirstWordConfidence[0] =
-                computeFirstWordConfidence(&terminals[0]);
-    }
     const bool boostExactMatches = traverseSession->getDictionaryStructurePolicy()->
             getHeaderStructurePolicy()->shouldBoostExactMatches();
+
+    int codePoints[MAX_WORD_LENGTH];
     // Output suggestion results here
-    for (int terminalIndex = 0; terminalIndex < terminalSize && outputWordIndex < MAX_RESULTS;
-            ++terminalIndex) {
+    for (int terminalIndex = 0; terminalIndex < terminalSize; ++terminalIndex) {
         DicNode *terminalDicNode = &terminals[terminalIndex];
         if (DEBUG_GEO_FULL) {
             terminalDicNode->dump("OUT:");
@@ -118,25 +102,18 @@
                 (forceCommitMultiWords && terminalDicNode->hasMultipleWords())
                          || (isValidWord && scoringPolicy->doesAutoCorrectValidWord()),
                 boostExactMatches);
-        if (maxScore < finalScore && isValidWord) {
-            maxScore = finalScore;
-        }
 
         // Don't output invalid words. However, we still need to submit their shortcuts if any.
         if (isValidWord) {
-            outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION | outputTypeFlags;
-            outputScores[outputWordIndex] = finalScore;
-            if (outputSecondWordFirstLetterInputIndex) {
-                outputIndicesToPartialCommit[outputWordIndex] =
-                        terminalDicNode->getSecondWordFirstInputIndex(
-                                traverseSession->getProximityInfoState(0));
-            } else {
-                outputIndicesToPartialCommit[outputWordIndex] = NOT_AN_INDEX;
-            }
-            // Populate the outputChars array with the suggested word.
-            const int startIndex = outputWordIndex * MAX_WORD_LENGTH;
-            terminalDicNode->outputResult(&outputCodePoints[startIndex]);
-            ++outputWordIndex;
+            terminalDicNode->outputResult(codePoints);
+            const int indexToPartialCommit = outputSecondWordFirstLetterInputIndex ?
+                    terminalDicNode->getSecondWordFirstInputIndex(
+                            traverseSession->getProximityInfoState(0)) :
+                    NOT_AN_INDEX;
+            outSuggestionResults->addSuggestion(codePoints,
+                    terminalDicNode->getTotalNodeCodePointCount(),
+                    finalScore, Dictionary::KIND_CORRECTION | outputTypeFlags,
+                    indexToPartialCommit, computeFirstWordConfidence(terminalDicNode));
         }
 
         if (!terminalDicNode->hasMultipleWords()) {
@@ -152,28 +129,11 @@
                              traverseSession->getInputSize(),
                              terminalDicNode->getContainedErrorTypes(),
                              true /* forceCommit */, boostExactMatches) : finalScore;
-            const int updatedOutputWordIndex = outputShortcuts(&shortcutIt,
-                    outputWordIndex, shortcutBaseScore, outputCodePoints, outputScores, outputTypes,
-                    sameAsTyped);
-            const int secondWordFirstInputIndex = terminalDicNode->getSecondWordFirstInputIndex(
-                    traverseSession->getProximityInfoState(0));
-            for (int i = outputWordIndex; i < updatedOutputWordIndex; ++i) {
-                if (outputSecondWordFirstLetterInputIndex) {
-                    outputIndicesToPartialCommit[i] = secondWordFirstInputIndex;
-                } else {
-                    outputIndicesToPartialCommit[i] = NOT_AN_INDEX;
-                }
-            }
-            outputWordIndex = updatedOutputWordIndex;
+            outputShortcuts(&shortcutIt, shortcutBaseScore, sameAsTyped, outSuggestionResults);
         }
         DicNode::managedDelete(terminalDicNode);
     }
-
-    if (hasMostProbableString) {
-        scoringPolicy->safetyNetForMostProbableString(outputWordIndex, maxScore,
-                &outputCodePoints[0], outputScores);
-    }
-    return outputWordIndex;
+    scoringPolicy->getMostProbableString(traverseSession, languageWeight, outSuggestionResults);
 }
 
 /* static */ int SuggestionsOutputUtils::computeFirstWordConfidence(
@@ -228,12 +188,11 @@
     return distanceContribution + lengthContribution + spaceContribution;
 }
 
-/* static */ int SuggestionsOutputUtils::outputShortcuts(
-        BinaryDictionaryShortcutIterator *const shortcutIt,
-        int outputWordIndex, const int finalScore, int *const outputCodePoints,
-        int *const outputScores, int *const outputTypes, const bool sameAsTyped) {
+/* static */ void SuggestionsOutputUtils::outputShortcuts(
+        BinaryDictionaryShortcutIterator *const shortcutIt, const int finalScore,
+        const bool sameAsTyped, SuggestionResults *const outSuggestionResults) {
     int shortcutTarget[MAX_WORD_LENGTH];
-    while (shortcutIt->hasNextShortcutTarget() && outputWordIndex < MAX_RESULTS) {
+    while (shortcutIt->hasNextShortcutTarget()) {
         bool isWhilelist;
         int shortcutTargetStringLength;
         shortcutIt->nextShortcutTarget(MAX_WORD_LENGTH, shortcutTarget,
@@ -250,14 +209,9 @@
             shortcutScore = std::max(S_INT_MIN + 1, shortcutScore) - 1;
             kind = Dictionary::KIND_SHORTCUT;
         }
-        outputTypes[outputWordIndex] = kind;
-        outputScores[outputWordIndex] = shortcutScore;
-        outputScores[outputWordIndex] = std::max(S_INT_MIN + 1, shortcutScore) - 1;
-        const int startIndex2 = outputWordIndex * MAX_WORD_LENGTH;
-        DicNodeUtils::appendTwoWords(0, 0, shortcutTarget, shortcutTargetStringLength,
-                &outputCodePoints[startIndex2]);
-        ++outputWordIndex;
+        outSuggestionResults->addSuggestion(shortcutTarget, shortcutTargetStringLength,
+                std::max(S_INT_MIN + 1, shortcutScore) - 1, kind, NOT_AN_INDEX,
+                NOT_A_FIRST_WORD_CONFIDENCE);
     }
-    return outputWordIndex;
 }
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.h b/native/jni/src/suggest/core/result/suggestions_output_utils.h
index d456a54..26d4b40 100644
--- a/native/jni/src/suggest/core/result/suggestions_output_utils.h
+++ b/native/jni/src/suggest/core/result/suggestions_output_utils.h
@@ -25,16 +25,15 @@
 class DicNode;
 class DicTraverseSession;
 class Scoring;
+class SuggestionResults;
 
 class SuggestionsOutputUtils {
  public:
     /**
      * Outputs the final list of suggestions (i.e., terminal nodes).
      */
-    static int outputSuggestions(const Scoring *const scoringPolicy,
-            DicTraverseSession *traverseSession, int *outputScores, int *outputCodePoints,
-            int *outputIndicesToPartialCommit, int *outputTypes,
-            int *outputAutoCommitFirstWordConfidence);
+    static void outputSuggestions(const Scoring *const scoringPolicy,
+            DicTraverseSession *traverseSession, SuggestionResults *const outSuggestionResults);
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(SuggestionsOutputUtils);
@@ -44,9 +43,9 @@
 
     static int computeFirstWordConfidence(const DicNode *const terminalDicNode);
 
-    static int outputShortcuts(BinaryDictionaryShortcutIterator *const shortcutIt,
-            int outputWordIndex, const int finalScore, int *const outputCodePoints,
-            int *const outputScores, int *const outputTypes, const bool sameAsTyped);
+    static void outputShortcuts(BinaryDictionaryShortcutIterator *const shortcutIt,
+            const int finalScore, const bool sameAsTyped,
+            SuggestionResults *const outSuggestionResults);
 };
 } // namespace latinime
 #endif // LATINIME_SUGGESTIONS_OUTPUT_UTILS
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index f6de571..2ea6452 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -42,10 +42,9 @@
  * automatically activated for sequential calls that share the same starting input.
  * TODO: Stop detecting continuous suggestion. Start using traverseSession instead.
  */
-int Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession,
+void Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession,
         int *inputXs, int *inputYs, int *times, int *pointerIds, int *inputCodePoints,
-        int inputSize, int *outWords, int *outputScores, int *outputIndices,
-        int *outputTypes, int *outputAutoCommitFirstWordConfidence) const {
+        int inputSize, SuggestionResults *const outSuggestionResults) const {
     PROF_OPEN;
     PROF_START(0);
     const float maxSpatialDistance = TRAVERSAL->getMaxSpatialDistance();
@@ -66,11 +65,9 @@
     }
     PROF_END(1);
     PROF_START(2);
-    const int size = SuggestionsOutputUtils::outputSuggestions(SCORING, tSession, outputScores,
-            outWords, outputIndices, outputTypes, outputAutoCommitFirstWordConfidence);
+    SuggestionsOutputUtils::outputSuggestions(SCORING, tSession, outSuggestionResults);
     PROF_END(2);
     PROF_CLOSE;
-    return size;
 }
 
 /**
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index 33ea0b6..13ad621 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -36,6 +36,7 @@
 class DicTraverseSession;
 class ProximityInfo;
 class Scoring;
+class SuggestionResults;
 class Traversal;
 class Weighting;
 
@@ -46,10 +47,9 @@
               SCORING(suggestPolicy ? suggestPolicy->getScoring() : nullptr),
               WEIGHTING(suggestPolicy ? suggestPolicy->getWeighting() : nullptr) {}
     AK_FORCE_INLINE virtual ~Suggest() {}
-    int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs,
-            int *times, int *pointerIds, int *inputCodePoints, int inputSize, int *outWords,
-            int *outputScores, int *outputIndices, int *outputTypes,
-            int *outputAutoCommitFirstWordConfidence) const;
+    void getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs,
+            int *times, int *pointerIds, int *inputCodePoints, int inputSize,
+            SuggestionResults *const outSuggestionResults) const;
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Suggest);
diff --git a/native/jni/src/suggest/core/suggest_interface.h b/native/jni/src/suggest/core/suggest_interface.h
index f10db83..c3ffea9 100644
--- a/native/jni/src/suggest/core/suggest_interface.h
+++ b/native/jni/src/suggest/core/suggest_interface.h
@@ -22,13 +22,13 @@
 namespace latinime {
 
 class ProximityInfo;
+class SuggestionResults;
 
 class SuggestInterface {
  public:
-    virtual int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs,
+    virtual void getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs,
             int *inputYs, int *times, int *pointerIds, int *inputCodePoints, int inputSize,
-            int *outWords, int *outputScores, int *outputIndices, int *outputTypes,
-            int *outputAutoCommitFirstWordConfidence) const = 0;
+            SuggestionResults *const suggestionResults) const = 0;
     SuggestInterface() {}
     virtual ~SuggestInterface() {}
  private:
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
index 8982800..66ea624 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
@@ -32,15 +32,8 @@
  public:
     static const TypingScoring *getInstance() { return &sInstance; }
 
-    AK_FORCE_INLINE bool getMostProbableString(const DicTraverseSession *const traverseSession,
-            const int terminalSize, const float languageWeight, int *const outputCodePoints,
-            int *const type, int *const freq) const {
-        return false;
-    }
-
-    AK_FORCE_INLINE void safetyNetForMostProbableString(const int scoreCount, const int maxScore,
-            int *const outputCodePoints, int *const scores) const {
-    }
+    AK_FORCE_INLINE void getMostProbableString(const DicTraverseSession *const traverseSession,
+            const float languageWeight, SuggestionResults *const outSuggestionResults) const {}
 
     AK_FORCE_INLINE float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession,
             DicNode *const terminals, const int size) const {
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
index 918f090..ae2205b 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
@@ -20,6 +20,7 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Pair;
 
+import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.CodePointUtils;
 import com.android.inputmethod.latin.makedict.DictDecoder;
 import com.android.inputmethod.latin.makedict.DictionaryHeader;
@@ -151,7 +152,8 @@
         binaryDictionary.flushWithGC();
         binaryDictionary.close();
 
-        final DictDecoder dictDecoder = FormatSpec.getDictDecoder(dictFile, 0, dictFile.length());
+        final DictDecoder dictDecoder =
+                BinaryDictIOUtils.getDictDecoder(dictFile, 0, dictFile.length());
         try {
             final FusionDictionary dict =
                     dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */);
diff --git a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index 4bf6174..f29fc21 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -251,7 +251,7 @@
 
         FusionDictionary dict = null;
         try {
-            final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, 0, file.length(),
+            final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length(),
                     bufferType);
             now = System.currentTimeMillis();
             dict = dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */);
@@ -414,7 +414,7 @@
 
         long now = -1, diff = -1;
         try {
-            final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, 0, file.length(),
+            final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length(),
                     bufferType);
             now = System.currentTimeMillis();
             dictDecoder.readUnigramsAndBigramsBinary(resultWords, resultFreqs, resultBigrams);
@@ -539,7 +539,7 @@
         addBigrams(dict, words, bigrams);
         timeWritingDictToFile(file, dict, formatOptions);
 
-        final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, 0, file.length(),
+        final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length(),
                 DictDecoder.USE_BYTEARRAY);
         try {
             dictDecoder.openDictBuffer();
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
rename to tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
index b534bcb..6f8b07a 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
@@ -28,7 +28,6 @@
  *
  * All the methods in this class are static.
  *
- * TODO: Remove calls from classes except Ver3DictDecoder
  * TODO: Move this file to makedict/internal.
  * TODO: Rename this class to DictDecoderUtils.
  */
@@ -356,7 +355,7 @@
      * @return true if it's a binary dictionary, false otherwise
      */
     public static boolean isBinaryDictionary(final File file) {
-        final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, 0, file.length());
+        final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length());
         if (dictDecoder == null) {
             return false;
         }
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
rename to tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
similarity index 88%
rename from java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
rename to tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
index a180f1c..42a50be 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
@@ -18,7 +18,9 @@
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -32,6 +34,38 @@
         // This utility class is not publicly instantiable.
     }
 
+    /**
+     * Returns new dictionary decoder.
+     *
+     * @param dictFile the dictionary file.
+     * @param bufferType The type of buffer, as one of USE_* in DictDecoder.
+     * @return new dictionary decoder if the dictionary file exists, otherwise null.
+     */
+    public static DictDecoder getDictDecoder(final File dictFile, final long offset,
+            final long length, final int bufferType) {
+        if (dictFile.isDirectory()) {
+            return new Ver4DictDecoder(dictFile, bufferType);
+        } else if (dictFile.isFile()) {
+            return new Ver2DictDecoder(dictFile, offset, length, bufferType);
+        }
+        return null;
+    }
+
+    public static DictDecoder getDictDecoder(final File dictFile, final long offset,
+            final long length, final DictionaryBufferFactory factory) {
+        if (dictFile.isDirectory()) {
+            return new Ver4DictDecoder(dictFile, factory);
+        } else if (dictFile.isFile()) {
+            return new Ver2DictDecoder(dictFile, offset, length, factory);
+        }
+        return null;
+    }
+
+    public static DictDecoder getDictDecoder(final File dictFile, final long offset,
+            final long length) {
+        return getDictDecoder(dictFile, offset, length, DictDecoder.USE_READONLY_BYTEBUFFER);
+    }
+
     private static final class Position {
         public static final int NOT_READ_PTNODE_COUNT = -1;
 
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/DictDecoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/DictDecoder.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java b/tests/src/com/android/inputmethod/latin/makedict/DictEncoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/DictEncoder.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
rename to tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/makedict/MakedictLog.java b/tests/src/com/android/inputmethod/latin/makedict/MakedictLog.java
similarity index 100%
rename from tools/dicttool/src/com/android/inputmethod/latin/makedict/MakedictLog.java
rename to tests/src/com/android/inputmethod/latin/makedict/MakedictLog.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/PendingAttribute.java b/tests/src/com/android/inputmethod/latin/makedict/PendingAttribute.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/PendingAttribute.java
rename to tests/src/com/android/inputmethod/latin/makedict/PendingAttribute.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java b/tests/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
rename to tests/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
rename to tests/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
diff --git a/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java b/tests/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
similarity index 100%
rename from java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
rename to tests/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index 0e9c14e..f49dee7 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -30,11 +30,12 @@
 LATINIME_BASE_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/java/src/com/android/inputmethod
 LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annotations
 MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/makedict
+LATINIME_TESTS_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin
 
 # Dependencies for Dicttool. Most of these files are needed by BinaryDictionary.java. Note that
 # a significant part of the dependencies are mocked in the compat/ directory, with empty or
 # nearly-empty implementations, for parts that we don't use in Dicttool.
-LATINIME_SRCS_FOR_DICTTOOL := \
+LATINIME_SRC_FILES_FOR_DICTTOOL := \
         event/Combiner.java \
         event/Event.java \
         latin/BinaryDictionary.java \
@@ -47,7 +48,6 @@
         latin/WordComposer.java \
         latin/settings/NativeSuggestOptions.java \
         latin/utils/BinaryDictionaryUtils.java \
-        latin/utils/ByteArrayDictBuffer.java \
         latin/utils/CollectionUtils.java \
         latin/utils/CombinedFormatUtils.java \
         latin/utils/CoordinateUtils.java \
@@ -56,8 +56,13 @@
         latin/utils/LocaleUtils.java \
         latin/utils/ResizableIntArray.java \
         latin/utils/StringUtils.java
-USED_TARGETED_SRCS := $(addprefix $(LATINIME_BASE_SOURCE_DIRECTORY)/, \
-        $(LATINIME_SRCS_FOR_DICTTOOL))
+
+LATINIME_TEST_SRC_FILES_FOR_DICTTOOL := \
+        utils/ByteArrayDictBuffer.java
+
+USED_TARGETED_SRCS := \
+        $(addprefix $(LATINIME_BASE_SOURCE_DIRECTORY)/, $(LATINIME_SRC_FILES_FOR_DICTTOOL)) \
+        $(addprefix $(LATINIME_TESTS_SOURCE_DIRECTORY)/, $(LATINIME_TEST_SRC_FILES_FOR_DICTTOOL))
 
 DICTTOOL_ONDEVICE_TESTS_DIRECTORY := \
         $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin/makedict/
@@ -70,12 +75,11 @@
 
 LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \
         $(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \
-        $(LOCAL_ANNOTATIONS_SRC_FILES) \
+        $(call all-java-files-under, $(DICTTOOL_COMPAT_TESTS_DIRECTORY)) \
+        $(LOCAL_ANNOTATIONS_SRC_FILES) $(USED_TARGETED_SRCS) \
         $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/Constants.java \
         $(call all-java-files-under, tests) \
-        $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY)) \
-        $(call all-java-files-under, $(DICTTOOL_COMPAT_TESTS_DIRECTORY)) \
-        $(USED_TARGETED_SRCS)
+        $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY))
 
 LOCAL_JAVA_LIBRARIES := junit
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LATINIME_HOST_NATIVE_LIBNAME)
diff --git a/tools/dicttool/NativeLib.mk b/tools/dicttool/NativeLib.mk
index 95f767d..0d3507b 100644
--- a/tools/dicttool/NativeLib.mk
+++ b/tools/dicttool/NativeLib.mk
@@ -37,9 +37,9 @@
 LOCAL_CFLAGS += -DHOST_TOOL -fPIC -Wno-deprecated
 LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
 
+LOCAL_CLANG := true
 # For C++11
-# TODO: Change this to -std=c++11
-LOCAL_CFLAGS += -std=gnu++0x
+LOCAL_CFLAGS += -std=c++11
 
 LATINIME_NATIVE_JNI_DIR := $(LATINIME_DIR_RELATIVE_TO_DICTTOOL)/native/jni
 LATINIME_NATIVE_SRC_DIR := $(LATINIME_DIR_RELATIVE_TO_DICTTOOL)/native/jni/src
diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java b/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java
index c68bdaa..d6d5e2d 100644
--- a/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java
+++ b/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java
@@ -21,5 +21,5 @@
         // This class is not publicly instantiable.
     }
 
-    public static final String JNI_LIB_NAME = "latinime-dicttool-host";
+    public static final String JNI_LIB_NAME = "latinime-aosp-dicttool-host";
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
index e31ac2a..f9771c8 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin.dicttool;
 
 import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
+import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.DictDecoder;
 import com.android.inputmethod.latin.makedict.FormatSpec;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
@@ -191,8 +192,9 @@
                     return CombinedInputOutput.readDictionaryCombined(
                             new BufferedInputStream(new FileInputStream(decodedSpec.mFile)));
                 } else {
-                    final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodedSpec.mFile,
-                            0, decodedSpec.mFile.length(), DictDecoder.USE_BYTEARRAY);
+                    final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(
+                            decodedSpec.mFile, 0, decodedSpec.mFile.length(),
+                            DictDecoder.USE_BYTEARRAY);
                     if (report) {
                         System.out.println("Format : Binary dictionary format");
                         System.out.println("Packaging : " + decodedSpec.describeChain());
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
index 68d7850..8e8ab19 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin.dicttool;
 
 import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
+import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.DictDecoder;
 import com.android.inputmethod.latin.makedict.DictEncoder;
 import com.android.inputmethod.latin.makedict.FormatSpec;
@@ -264,7 +265,7 @@
     private static FusionDictionary readBinaryFile(final String binaryFilename)
             throws FileNotFoundException, IOException, UnsupportedFormatException {
         final File file = new File(binaryFilename);
-        final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, 0, file.length());
+        final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length());
         return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */);
     }
 
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
index a3095da..4f1273b 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin.dicttool;
 
+import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.DictDecoder;
 import com.android.inputmethod.latin.makedict.DictEncoder;
 import com.android.inputmethod.latin.makedict.DictionaryHeader;
@@ -77,7 +79,7 @@
             assertEquals("Wrong decode spec", BinaryDictOffdeviceUtils.COMPRESSION, step);
         }
         assertEquals("Wrong decode spec", 3, decodeSpec.mDecoderSpec.size());
-        final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodeSpec.mFile, 0,
+        final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(decodeSpec.mFile, 0,
                 decodeSpec.mFile.length());
         final FusionDictionary resultDict =
                 dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */);