Merge "Remove unnecessary variables"
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 8459850..6c66a48 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -85,11 +85,6 @@
     <!-- Description for option enabling or disabling the use of names of people in Contacts for suggestion and correction [CHAR LIMIT=65] -->
     <string name="use_contacts_dict_summary">Use names from Contacts for suggestions and corrections</string>
 
-    <!-- Option name for enabling insertion of suggestion spans (advanced option) [CHAR LIMIT=25] -->
-    <string name="enable_span_insert">Enable recorrections</string>
-    <!-- Option summary for enabling insertion of suggestion spans (advanced option) [CHAR LIMIT=65] -->
-    <string name="enable_span_insert_summary">Set suggestions for recorrections</string>
-
     <!-- Option to enable auto capitalization of sentences -->
     <string name="auto_cap">Auto-capitalization</string>
 
@@ -120,14 +115,10 @@
     <!-- Option to suggest auto correction suggestions very aggressively. Auto-corrects to a word which has even large edit distance from typed word. [CHAR LIMIT=20] -->
     <string name="auto_correction_threshold_mode_very_aggeressive">Very aggressive</string>
 
-    <!-- Option to enable next word correction -->
-    <string name="bigram_suggestion">Next word suggestions</string>
-    <!-- Option to enable next word suggestion. This uses the previous word in an attempt to improve the suggestions quality -->
-    <string name="bigram_suggestion_summary">Use previous word to improve suggestions</string>
-    <!-- Option to enable using next word prediction -->
-    <string name="bigram_prediction">Next word prediction</string>
-    <!-- Description for "next word prediction" option. This displays suggestions even when there is no input, based on the previous word. -->
-    <string name="bigram_prediction_summary">Use previous word also for prediction</string>
+    <!-- Option to enable using next word suggestions. After the user types a space, with this option on, the keyboard will try to predict the next word. -->
+    <string name="bigram_prediction">Next word suggestions</string>
+    <!-- Description for "next word suggestion" option. This displays suggestions even when there is no input, based on the previous word. -->
+    <string name="bigram_prediction_summary">Based on previous word</string>
 
     <!-- Indicates that a word has been added to the dictionary -->
     <string name="added_word"><xliff:g id="word">%s</xliff:g> : Saved</string>
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 042a1c0..7714ba8 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -758,15 +758,18 @@
                 final PointerTracker tracker = PointerTracker.getPointerTracker(
                         pointerId, this);
                 final int px, py;
+                final MotionEvent motionEvent;
                 if (mMoreKeysPanel != null
                         && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) {
                     px = mMoreKeysPanel.translateX((int)me.getX(i));
                     py = mMoreKeysPanel.translateY((int)me.getY(i));
+                    motionEvent = null;
                 } else {
                     px = (int)me.getX(i);
                     py = (int)me.getY(i);
+                    motionEvent = me;
                 }
-                tracker.onMoveEvent(px, py, eventTime);
+                tracker.onMoveEvent(px, py, eventTime, motionEvent);
                 if (ENABLE_USABILITY_STUDY_LOG) {
                     final float pointerSize = me.getSize(i);
                     final float pointerPressure = me.getPressure(i);
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 7ab68d9..32ef408 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -469,7 +469,7 @@
             onUpEvent(x, y, eventTime);
             break;
         case MotionEvent.ACTION_MOVE:
-            onMoveEvent(x, y, eventTime);
+            onMoveEvent(x, y, eventTime, null);
             break;
         case MotionEvent.ACTION_CANCEL:
             onCancelEvent(x, y, eventTime);
@@ -548,7 +548,7 @@
         mIsInSlidingKeyInput = true;
     }
 
-    public void onMoveEvent(int x, int y, long eventTime) {
+    public void onMoveEvent(int x, int y, long eventTime, MotionEvent me) {
         if (DEBUG_MOVE_EVENT)
             printTouchEvent("onMoveEvent:", x, y, eventTime);
         if (mKeyAlreadyProcessed)
@@ -760,14 +760,10 @@
         callListenerOnRelease(key, code, false);
     }
 
-    private long mPreviousEventTime;
-
     private void printTouchEvent(String title, int x, int y, long eventTime) {
         final Key key = mKeyDetector.detectHitKey(x, y);
         final String code = KeyDetector.printableCode(key);
-        final long delta = eventTime - mPreviousEventTime;
         Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title,
-                (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, code));
-        mPreviousEventTime = eventTime;
+                (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, eventTime, code));
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 6b6ec2b..f44e632 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -108,7 +108,7 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getBigrams(final WordComposer codes,
-            final CharSequence previousWord, final WordCallback callback) {
+            final CharSequence previousWord) {
         if (mNativeDict == 0) return null;
 
         int[] codePoints = StringUtils.toCodePointArray(previousWord.toString());
@@ -141,15 +141,13 @@
                         mBigramScores[j], SuggestedWordInfo.KIND_CORRECTION));
             }
         }
-        Utils.addAllSuggestions(mDicTypeId, Dictionary.BIGRAM, suggestions, callback);
         return suggestions;
     }
 
     // proximityInfo and/or prevWordForBigrams may not be null.
     @Override
     public ArrayList<SuggestedWordInfo> getWords(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars,
                 mScores, mSpaceIndices);
 
@@ -168,7 +166,6 @@
                         mScores[j], SuggestedWordInfo.KIND_CORRECTION));
             }
         }
-        Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback);
         return suggestions;
     }
 
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 55913b8..99a04da 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -35,52 +35,26 @@
     public static final int BIGRAM = 1;
 
     public static final int NOT_A_PROBABILITY = -1;
-    /**
-     * Interface to be implemented by classes requesting words to be fetched from the dictionary.
-     * @see #getWords(WordComposer, CharSequence, WordCallback, ProximityInfo)
-     */
-    public interface WordCallback {
-        /**
-         * Adds a word to a list of suggestions. The word is expected to be ordered based on
-         * the provided score.
-         * @param word the character array containing the word
-         * @param spaceIndices the indices of inserted spaces
-         * @param wordOffset starting offset of the word in the character array
-         * @param wordLength length of valid characters in the character array
-         * @param score the score of occurrence. This is normalized between 1 and 255, but
-         * can exceed those limits
-         * @param dicTypeId of the dictionary where word was from
-         * @param dataType tells type of this data, either UNIGRAM or BIGRAM
-         * @return true if the word was added, false if no more words are required
-         */
-        boolean addWord(char[] word, int[] spaceIndices, int wordOffset, int wordLength, int score,
-                int dicTypeId, int dataType);
-    }
 
     /**
      * Searches for words in the dictionary that match the characters in the composer. Matched
-     * words are added through the callback object.
-     * @param composer the key sequence to match
+     * words are returned as an ArrayList.
+     * @param composer the key sequence to match with coordinate info, as a WordComposer
      * @param prevWordForBigrams the previous word, or null if none
-     * @param callback the callback object to send matched words to as possible candidates
      * @param proximityInfo the object for key proximity. May be ignored by some implementations.
      * @return the list of suggestions
-     * @see WordCallback#addWord(char[], int, int, int, int, int)
      */
     abstract public ArrayList<SuggestedWordInfo> getWords(final WordComposer composer,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo);
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo);
 
     /**
-     * Searches for pairs in the bigram dictionary that matches the previous word and all the
-     * possible words following are added through the callback object.
+     * Searches for pairs in the bigram dictionary that matches the previous word.
      * @param composer the key sequence to match
      * @param previousWord the word before
-     * @param callback the callback object to send possible word following previous word
      * @return the list of suggestions
      */
     public abstract ArrayList<SuggestedWordInfo> getBigrams(final WordComposer composer,
-            final CharSequence previousWord, final WordCallback callback);
+            final CharSequence previousWord);
 
     /**
      * Checks if the given word occurs in the dictionary
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index 6b424f8..169e707 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -53,19 +53,18 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getWords(final WordComposer composer,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
         if (dictionaries.isEmpty()) return null;
         // To avoid creating unnecessary objects, we get the list out of the first
         // dictionary and add the rest to it if not null, hence the get(0)
         ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getWords(composer,
-                prevWordForBigrams, callback, proximityInfo);
+                prevWordForBigrams, proximityInfo);
         if (null == suggestions) suggestions = new ArrayList<SuggestedWordInfo>();
         final int length = dictionaries.size();
         for (int i = 0; i < length; ++ i) {
             final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getWords(composer,
-                    prevWordForBigrams, callback, proximityInfo);
+                    prevWordForBigrams, proximityInfo);
             if (null != sugg) suggestions.addAll(sugg);
         }
         return suggestions;
@@ -73,18 +72,18 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getBigrams(final WordComposer composer,
-            final CharSequence previousWord, final WordCallback callback) {
+            final CharSequence previousWord) {
         final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
         if (dictionaries.isEmpty()) return null;
         // To avoid creating unnecessary objects, we get the list out of the first
         // dictionary and add the rest to it if not null, hence the get(0)
         ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getBigrams(composer,
-                previousWord, callback);
+                previousWord);
         if (null == suggestions) suggestions = new ArrayList<SuggestedWordInfo>();
         final int length = dictionaries.size();
         for (int i = 0; i < length; ++ i) {
             final ArrayList<SuggestedWordInfo> sugg =
-                    dictionaries.get(i).getBigrams(composer, previousWord, callback);
+                   dictionaries.get(i).getBigrams(composer, previousWord);
             if (null != sugg) suggestions.addAll(sugg);
         }
         return suggestions;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 732bc18..c076fa0 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -196,22 +196,19 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getWords(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         asyncReloadDictionaryIfRequired();
-        return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo);
+        return getWordsInner(codes, prevWordForBigrams, proximityInfo);
     }
 
     protected final ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         // Ensure that there are no concurrent calls to getWords. If there are, do nothing and
         // return.
         if (mLocalDictionaryController.tryLock()) {
             try {
                 if (mBinaryDictionary != null) {
-                    return mBinaryDictionary.getWords(codes, prevWordForBigrams, callback,
-                            proximityInfo);
+                    return mBinaryDictionary.getWords(codes, prevWordForBigrams, proximityInfo);
                 }
             } finally {
                 mLocalDictionaryController.unlock();
@@ -222,17 +219,17 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getBigrams(final WordComposer codes,
-            final CharSequence previousWord, final WordCallback callback) {
+            final CharSequence previousWord) {
         asyncReloadDictionaryIfRequired();
-        return getBigramsInner(codes, previousWord, callback);
+        return getBigramsInner(codes, previousWord);
     }
 
     protected ArrayList<SuggestedWordInfo> getBigramsInner(final WordComposer codes,
-            final CharSequence previousWord, final WordCallback callback) {
+            final CharSequence previousWord) {
         if (mLocalDictionaryController.tryLock()) {
             try {
                 if (mBinaryDictionary != null) {
-                    return mBinaryDictionary.getBigrams(codes, previousWord, callback);
+                    return mBinaryDictionary.getBigrams(codes, previousWord);
                 }
             } finally {
                 mLocalDictionaryController.unlock();
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 7d131a6..f19d77b 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -249,8 +249,7 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getWords(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         synchronized (mUpdatingLock) {
             // If we need to update, start off a background task
             if (mRequiresReload) startDictionaryLoadingTaskLocked();
@@ -262,7 +261,6 @@
         }
         final ArrayList<SuggestedWordInfo> suggestions =
                 getWordsInner(codes, prevWordForBigrams, proximityInfo);
-        Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback);
         return suggestions;
     }
 
@@ -614,11 +612,10 @@
 
     @Override
     public ArrayList<SuggestedWordInfo> getBigrams(final WordComposer codes,
-            final CharSequence previousWord, final WordCallback callback) {
+            final CharSequence previousWord) {
         if (!reloadDictionaryIfRequired()) {
             final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<SuggestedWordInfo>();
             runBigramReverseLookUp(previousWord, suggestions);
-            Utils.addAllSuggestions(mDicTypeId, Dictionary.BIGRAM, suggestions, callback);
             return suggestions;
         }
         return null;
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 61a8e28..a433293 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.concurrent.ConcurrentHashMap;
@@ -34,7 +35,7 @@
  * This class loads a dictionary and provides a list of suggestions for a given sequence of
  * characters. This includes corrections and completions.
  */
-public class Suggest implements Dictionary.WordCallback {
+public class Suggest {
     public static final String TAG = Suggest.class.getSimpleName();
 
     public static final int APPROX_MAX_WORD_LENGTH = 32;
@@ -58,53 +59,61 @@
     public static final String DICT_KEY_CONTACTS = "contacts";
     // User dictionary, the system-managed one.
     public static final String DICT_KEY_USER = "user";
-    // User history dictionary for the unigram map, internal to LatinIME
-    public static final String DICT_KEY_USER_HISTORY_UNIGRAM = "history_unigram";
-    // User history dictionary for the bigram map, internal to LatinIME
-    public static final String DICT_KEY_USER_HISTORY_BIGRAM = "history_bigram";
+    // User history dictionary internal to LatinIME
+    public static final String DICT_KEY_USER_HISTORY = "history";
     public static final String DICT_KEY_WHITELIST ="whitelist";
+    // TODO: remove this map. This only serves as backward compatibility with a feature
+    // that has never been used and has been broken for a while.
+    private static final HashMap<String, Integer> sDictKeyToDictIndex
+            = new HashMap<String, Integer>();
+    static {
+        sDictKeyToDictIndex.put(DICT_KEY_MAIN, DIC_MAIN);
+        sDictKeyToDictIndex.put(DICT_KEY_USER, DIC_USER);
+        sDictKeyToDictIndex.put(DICT_KEY_USER_HISTORY, DIC_USER_HISTORY);
+        sDictKeyToDictIndex.put(DICT_KEY_CONTACTS, DIC_CONTACTS);
+        sDictKeyToDictIndex.put(DICT_KEY_WHITELIST, DIC_WHITELIST);
+    }
 
     private static final boolean DBG = LatinImeLogger.sDBG;
 
     private Dictionary mMainDictionary;
     private ContactsBinaryDictionary mContactsDict;
     private WhitelistDictionary mWhiteListDictionary;
-    private final ConcurrentHashMap<String, Dictionary> mUnigramDictionaries =
-            new ConcurrentHashMap<String, Dictionary>();
-    private final ConcurrentHashMap<String, Dictionary> mBigramDictionaries =
+    private final ConcurrentHashMap<String, Dictionary> mDictionaries =
             new ConcurrentHashMap<String, Dictionary>();
 
     public static final int MAX_SUGGESTIONS = 18;
 
     private float mAutoCorrectionThreshold;
 
-    private ArrayList<SuggestedWordInfo> mSuggestions = new ArrayList<SuggestedWordInfo>();
-    private CharSequence mConsideredWord;
-
     // TODO: Remove these member variables by passing more context to addWord() callback method
     private boolean mIsFirstCharCapitalized;
     private boolean mIsAllUpperCase;
     private int mTrailingSingleQuotesCount;
 
+    // Locale used for upper- and title-casing words
+    final private Locale mLocale;
+
     private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
 
     public Suggest(final Context context, final Locale locale) {
         initAsynchronously(context, locale);
+        mLocale = locale;
     }
 
     /* package for test */ Suggest(final Context context, final File dictionary,
             final long startOffset, final long length, final Locale locale) {
         final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
                 startOffset, length /* useFullEditDistance */, false, locale);
+        mLocale = locale;
         mMainDictionary = mainDict;
-        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, mainDict);
-        addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, mainDict);
+        addOrReplaceDictionary(mDictionaries, DICT_KEY_MAIN, mainDict);
         initWhitelistAndAutocorrectAndPool(context, locale);
     }
 
     private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) {
         mWhiteListDictionary = new WhitelistDictionary(context, locale);
-        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary);
+        addOrReplaceDictionary(mDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary);
     }
 
     private void initAsynchronously(final Context context, final Locale locale) {
@@ -133,8 +142,7 @@
             public void run() {
                 final DictionaryCollection newMainDict =
                         DictionaryFactory.createMainDictionaryFromManager(context, locale);
-                addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, newMainDict);
-                addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, newMainDict);
+                addOrReplaceDictionary(mDictionaries, DICT_KEY_MAIN, newMainDict);
                 mMainDictionary = newMainDict;
             }
         }.start();
@@ -155,7 +163,7 @@
     }
 
     public ConcurrentHashMap<String, Dictionary> getUnigramDictionaries() {
-        return mUnigramDictionaries;
+        return mDictionaries;
     }
 
     public static int getApproxMaxWordLength() {
@@ -167,7 +175,7 @@
      * before the main dictionary, if set. This refers to the system-managed user dictionary.
      */
     public void setUserDictionary(UserBinaryDictionary userDictionary) {
-        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_USER, userDictionary);
+        addOrReplaceDictionary(mDictionaries, DICT_KEY_USER, userDictionary);
     }
 
     /**
@@ -177,15 +185,11 @@
      */
     public void setContactsDictionary(ContactsBinaryDictionary contactsDictionary) {
         mContactsDict = contactsDictionary;
-        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_CONTACTS, contactsDictionary);
-        addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_CONTACTS, contactsDictionary);
+        addOrReplaceDictionary(mDictionaries, DICT_KEY_CONTACTS, contactsDictionary);
     }
 
     public void setUserHistoryDictionary(UserHistoryDictionary userHistoryDictionary) {
-        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_USER_HISTORY_UNIGRAM,
-                userHistoryDictionary);
-        addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_USER_HISTORY_BIGRAM,
-                userHistoryDictionary);
+        addOrReplaceDictionary(mDictionaries, DICT_KEY_USER_HISTORY, userHistoryDictionary);
     }
 
     public void setAutoCorrectionThreshold(float threshold) {
@@ -209,39 +213,6 @@
         return sb;
     }
 
-    private static final WordComposer sEmptyWordComposer = new WordComposer();
-    public SuggestedWords getBigramPredictions(CharSequence prevWordForBigram) {
-        LatinImeLogger.onStartSuggestion(prevWordForBigram);
-        mIsFirstCharCapitalized = false;
-        mIsAllUpperCase = false;
-        mTrailingSingleQuotesCount = 0;
-        mSuggestions = new ArrayList<SuggestedWordInfo>(MAX_SUGGESTIONS);
-
-        // Treating USER_TYPED as UNIGRAM suggestion for logging now.
-        LatinImeLogger.onAddSuggestedWord("", Suggest.DIC_USER_TYPED, Dictionary.UNIGRAM);
-        mConsideredWord = "";
-
-        getAllBigrams(prevWordForBigram, sEmptyWordComposer);
-
-        SuggestedWordInfo.removeDups(mSuggestions);
-
-        return new SuggestedWords(mSuggestions,
-                false /* typedWordValid */,
-                false /* hasAutoCorrectionCandidate */,
-                false /* allowsToBeAutoCorrected */,
-                false /* isPunctuationSuggestions */,
-                false /* isObsoleteSuggestions */,
-                true /* isPrediction */);
-    }
-
-    // Compatibility for tests. TODO: remove this
-    public SuggestedWords getSuggestedWords(
-            final WordComposer wordComposer, CharSequence prevWordForBigram,
-            final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) {
-        return getSuggestedWords(wordComposer, prevWordForBigram, proximityInfo,
-                isCorrectionEnabled, false);
-    }
-
     // TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
     public SuggestedWords getSuggestedWords(
             final WordComposer wordComposer, CharSequence prevWordForBigram,
@@ -251,7 +222,8 @@
         mIsFirstCharCapitalized = !isPrediction && wordComposer.isFirstCharCapitalized();
         mIsAllUpperCase = !isPrediction && wordComposer.isAllUpperCase();
         mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
-        mSuggestions = new ArrayList<SuggestedWordInfo>(MAX_SUGGESTIONS);
+        final ArrayList<SuggestedWordInfo> suggestions =
+                new ArrayList<SuggestedWordInfo>(MAX_SUGGESTIONS);
 
         final String typedWord = wordComposer.getTypedWord();
         final String consideredWord = mTrailingSingleQuotesCount > 0
@@ -259,12 +231,32 @@
                 : typedWord;
         // Treating USER_TYPED as UNIGRAM suggestion for logging now.
         LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, Dictionary.UNIGRAM);
-        mConsideredWord = consideredWord;
 
         if (wordComposer.size() <= 1 && isCorrectionEnabled) {
             // At first character typed, search only the bigrams
             if (!TextUtils.isEmpty(prevWordForBigram)) {
-                getAllBigrams(prevWordForBigram, wordComposer);
+                final CharSequence lowerPrevWord;
+                if (StringUtils.hasUpperCase(prevWordForBigram)) {
+                    // TODO: Must pay attention to locale when changing case.
+                    lowerPrevWord = prevWordForBigram.toString().toLowerCase();
+                } else {
+                    lowerPrevWord = null;
+                }
+                for (final String key : mDictionaries.keySet()) {
+                    final int dicTypeId = sDictKeyToDictIndex.get(key);
+                    final Dictionary dictionary = mDictionaries.get(key);
+                    final ArrayList<SuggestedWordInfo> localSuggestions =
+                            dictionary.getBigrams(wordComposer, prevWordForBigram);
+                    if (null != lowerPrevWord) {
+                        localSuggestions.addAll(dictionary.getBigrams(wordComposer, lowerPrevWord));
+                    }
+                    for (final SuggestedWordInfo suggestion : localSuggestions) {
+                        final String suggestionStr = suggestion.mWord.toString();
+                        addWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(),
+                                suggestion.mScore, dicTypeId, Dictionary.BIGRAM,
+                                suggestions, consideredWord);
+                    }
+                }
             }
         } else if (wordComposer.size() > 1) {
             final WordComposer wordComposerForLookup;
@@ -277,12 +269,20 @@
                 wordComposerForLookup = wordComposer;
             }
             // At second character typed, search the unigrams (scores being affected by bigrams)
-            for (final String key : mUnigramDictionaries.keySet()) {
+            for (final String key : mDictionaries.keySet()) {
                 // Skip UserUnigramDictionary and WhitelistDictionary to lookup
-                if (key.equals(DICT_KEY_USER_HISTORY_UNIGRAM) || key.equals(DICT_KEY_WHITELIST))
+                if (key.equals(DICT_KEY_USER_HISTORY) || key.equals(DICT_KEY_WHITELIST))
                     continue;
-                final Dictionary dictionary = mUnigramDictionaries.get(key);
-                dictionary.getWords(wordComposerForLookup, prevWordForBigram, this, proximityInfo);
+                final int dicTypeId = sDictKeyToDictIndex.get(key);
+                final Dictionary dictionary = mDictionaries.get(key);
+                final ArrayList<SuggestedWordInfo> localSuggestions = dictionary.getWords(
+                        wordComposerForLookup, prevWordForBigram, proximityInfo);
+                for (final SuggestedWordInfo suggestion : localSuggestions) {
+                    final String suggestionStr = suggestion.mWord.toString();
+                    addWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(),
+                            suggestion.mScore, dicTypeId, Dictionary.UNIGRAM,
+                            suggestions, consideredWord);
+                }
             }
         }
 
@@ -292,8 +292,8 @@
         final boolean hasAutoCorrection;
         if (isCorrectionEnabled) {
             final CharSequence autoCorrection =
-                    AutoCorrection.computeAutoCorrectionWord(mUnigramDictionaries, wordComposer,
-                            mSuggestions, consideredWord, mAutoCorrectionThreshold,
+                    AutoCorrection.computeAutoCorrectionWord(mDictionaries, wordComposer,
+                            suggestions, consideredWord, mAutoCorrectionThreshold,
                             whitelistedWord);
             hasAutoCorrection = (null != autoCorrection);
         } else {
@@ -306,25 +306,25 @@
                 for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) {
                     sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE);
                 }
-                mSuggestions.add(0, new SuggestedWordInfo(sb.toString(),
+                suggestions.add(0, new SuggestedWordInfo(sb.toString(),
                         SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST));
             } else {
-                mSuggestions.add(0, new SuggestedWordInfo(whitelistedWord,
+                suggestions.add(0, new SuggestedWordInfo(whitelistedWord,
                         SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST));
             }
         }
 
         if (!isPrediction) {
-            mSuggestions.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
+            suggestions.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
                     SuggestedWordInfo.KIND_TYPED));
         }
-        SuggestedWordInfo.removeDups(mSuggestions);
+        SuggestedWordInfo.removeDups(suggestions);
 
         final ArrayList<SuggestedWordInfo> suggestionsList;
-        if (DBG && !mSuggestions.isEmpty()) {
-            suggestionsList = getSuggestionsInfoListWithDebugInfo(typedWord, mSuggestions);
+        if (DBG && !suggestions.isEmpty()) {
+            suggestionsList = getSuggestionsInfoListWithDebugInfo(typedWord, suggestions);
         } else {
-            suggestionsList = mSuggestions;
+            suggestionsList = suggestions;
         }
 
         // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
@@ -362,23 +362,6 @@
                 isPrediction);
     }
 
-    /**
-     * Adds all bigram predictions for prevWord. Also checks the lower case version of prevWord if
-     * it contains any upper case characters.
-     */
-    private void getAllBigrams(final CharSequence prevWord, final WordComposer wordComposer) {
-        if (StringUtils.hasUpperCase(prevWord)) {
-            // TODO: Must pay attention to locale when changing case.
-            final CharSequence lowerPrevWord = prevWord.toString().toLowerCase();
-            for (final Dictionary dictionary : mBigramDictionaries.values()) {
-                dictionary.getBigrams(wordComposer, lowerPrevWord, this);
-            }
-        }
-        for (final Dictionary dictionary : mBigramDictionaries.values()) {
-            dictionary.getBigrams(wordComposer, prevWord, this);
-        }
-    }
-
     private static ArrayList<SuggestedWordInfo> getSuggestionsInfoListWithDebugInfo(
             final String typedWord, final ArrayList<SuggestedWordInfo> suggestions) {
         final SuggestedWordInfo typedWordInfo = suggestions.get(0);
@@ -406,19 +389,16 @@
     }
 
     // TODO: Use codepoint instead of char
-    @Override
     public boolean addWord(final char[] word, int[] indices, final int offset, final int length,
-            int score, final int dicTypeId, final int dataType) {
+            int score, final int dicTypeId, final int dataType,
+            final ArrayList<SuggestedWordInfo> suggestions, final String consideredWord) {
         int dataTypeForLog = dataType;
-        final ArrayList<SuggestedWordInfo> suggestions;
-        final int prefMaxSuggestions;
-        suggestions = mSuggestions;
-        prefMaxSuggestions = MAX_SUGGESTIONS;
+        final int prefMaxSuggestions = MAX_SUGGESTIONS;
 
         int pos = 0;
 
         // Check if it's the same word, only caps are different
-        if (StringUtils.equalsIgnoreCase(mConsideredWord, word, offset, length)) {
+        if (StringUtils.equalsIgnoreCase(consideredWord, word, offset, length)) {
             // TODO: remove this surrounding if clause and move this logic to
             // getSuggestedWordBuilder.
             if (suggestions.size() > 0) {
@@ -476,8 +456,7 @@
 
     public void close() {
         final HashSet<Dictionary> dictionaries = new HashSet<Dictionary>();
-        dictionaries.addAll(mUnigramDictionaries.values());
-        dictionaries.addAll(mBigramDictionaries.values());
+        dictionaries.addAll(mDictionaries.values());
         for (final Dictionary dictionary : dictionaries) {
             dictionary.close();
         }
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
index d706022..74f27e3 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
@@ -33,10 +33,9 @@
 
     @Override
     public synchronized ArrayList<SuggestedWordInfo> getWords(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         syncReloadDictionaryIfRequired();
-        return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo);
+        return getWordsInner(codes, prevWordForBigrams, proximityInfo);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
index 984e2e7..5b2a6ed 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
@@ -36,10 +36,9 @@
 
     @Override
     public synchronized ArrayList<SuggestedWordInfo> getWords(final WordComposer codes,
-            final CharSequence prevWordForBigrams, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
+            final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) {
         syncReloadDictionaryIfRequired();
-        return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo);
+        return getWordsInner(codes, prevWordForBigrams, proximityInfo);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 19ac718..8f71de0 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -531,14 +531,4 @@
         }
         return builder.toString();
     }
-
-    public static void addAllSuggestions(final int dicTypeId, final int dataType,
-            final ArrayList<SuggestedWords.SuggestedWordInfo> suggestions,
-            final Dictionary.WordCallback callback) {
-        for (SuggestedWordInfo suggestion : suggestions) {
-            final String suggestionStr = suggestion.mWord.toString();
-            callback.addWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(),
-                    suggestion.mScore, dicTypeId, dataType);
-        }
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 0bbf2ac..5f4d660 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -32,12 +32,12 @@
 import com.android.inputmethod.latin.BinaryDictionary;
 import com.android.inputmethod.latin.ContactsBinaryDictionary;
 import com.android.inputmethod.latin.Dictionary;
-import com.android.inputmethod.latin.Dictionary.WordCallback;
 import com.android.inputmethod.latin.DictionaryCollection;
 import com.android.inputmethod.latin.DictionaryFactory;
 import com.android.inputmethod.latin.LocaleUtils;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary;
 import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary;
 import com.android.inputmethod.latin.UserBinaryDictionary;
@@ -203,7 +203,8 @@
                 EMPTY_STRING_ARRAY);
     }
 
-    private static class SuggestionsGatherer implements WordCallback {
+    // TODO: remove this class and replace it by storage local to the session.
+    private static class SuggestionsGatherer {
         public static class Result {
             public final String[] mSuggestions;
             public final boolean mHasRecommendedSuggestions;
@@ -237,9 +238,8 @@
             mScores = new int[mMaxLength];
         }
 
-        @Override
         synchronized public boolean addWord(char[] word, int[] spaceIndices, int wordOffset,
-                int wordLength, int score, int dicTypeId, int dataType) {
+                int wordLength, int score) {
             final int positionIndex = Arrays.binarySearch(mScores, 0, mLength, score);
             // binarySearch returns the index if the element exists, and -<insertion index> - 1
             // if it doesn't. See documentation for binarySearch.
@@ -780,8 +780,13 @@
                 try {
                     dictInfo = mDictionaryPool.takeOrGetNull();
                     if (null == dictInfo) return getNotInDictEmptySuggestions();
-                    dictInfo.mDictionary.getWords(composer, prevWord, suggestionsGatherer,
-                            dictInfo.mProximityInfo);
+                    final ArrayList<SuggestedWordInfo> suggestions = dictInfo.mDictionary.getWords(
+                            composer, prevWord, dictInfo.mProximityInfo);
+                    for (final SuggestedWordInfo suggestion : suggestions) {
+                        final String suggestionStr = suggestion.mWord.toString();
+                        suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
+                                suggestionStr.length(), suggestion.mScore);
+                    }
                     isInDict = dictInfo.mDictionary.isValidWord(text);
                     if (!isInDict && CAPITALIZE_NONE != capitalizeType) {
                         // We want to test the word again if it's all caps or first caps only.
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 3bb7b58..5d705b1 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -47,7 +47,8 @@
     dictionary.cpp \
     proximity_info.cpp \
     proximity_info_state.cpp \
-    unigram_dictionary.cpp
+    unigram_dictionary.cpp \
+    gesture/build_check.cpp
 
 LOCAL_SRC_FILES := \
     $(LATIN_IME_JNI_SRC_FILES) \
diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp
index 83bb267..e0b7f87 100644
--- a/native/jni/src/dictionary.cpp
+++ b/native/jni/src/dictionary.cpp
@@ -43,6 +43,8 @@
     mUnigramDictionary = new UnigramDictionary(mDict + headerSize, typedLetterMultiplier,
             fullWordMultiplier, maxWordLength, maxWords, options);
     mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength);
+    mGestureDecoder = new GestureDecoder(maxWordLength, maxWords);
+    mGestureDecoder->setDict(mUnigramDictionary, mBigramDictionary);
 }
 
 Dictionary::~Dictionary() {
diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h
index 76b25e5..708cb09 100644
--- a/native/jni/src/dictionary.h
+++ b/native/jni/src/dictionary.h
@@ -22,6 +22,7 @@
 #include "bigram_dictionary.h"
 #include "char_utils.h"
 #include "defines.h"
+#include "gesture/gesture_decoder.h"
 #include "proximity_info.h"
 #include "unigram_dictionary.h"
 #include "words_priority_queue_pool.h"
@@ -39,13 +40,20 @@
             bool useFullEditDistance, unsigned short *outWords,
             int *frequencies, int *spaceIndices) {
         int result = 0;
-        std::map<int, int> bigramMap;
-        uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE];
-        mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars,
-                prevWordLength, &bigramMap, bigramFilter);
-        result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates,
-                ycoordinates, codes, codesSize, &bigramMap, bigramFilter,
-                useFullEditDistance, outWords, frequencies);
+        if (isGesture) {
+            mGestureDecoder->setPrevWord(prevWordChars, prevWordLength);
+            result = mGestureDecoder->getSuggestions(proximityInfo, xcoordinates, ycoordinates,
+                    times, pointerIds, codes, codesSize, commitPoint, dicTypeId == 1 /* main */,
+                    outWords, frequencies, spaceIndices);
+        } else {
+            std::map<int, int> bigramMap;
+            uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE];
+            mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars,
+                    prevWordLength, &bigramMap, bigramFilter);
+            result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates,
+                    ycoordinates, codes, codesSize, &bigramMap, bigramFilter,
+                    useFullEditDistance, outWords, frequencies);
+        }
         return result;
     }
 
@@ -79,6 +87,7 @@
 
     const UnigramDictionary *mUnigramDictionary;
     const BigramDictionary *mBigramDictionary;
+    GestureDecoder *mGestureDecoder;
 };
 
 // public static utility methods
diff --git a/native/jni/src/gesture/build_check.cpp b/native/jni/src/gesture/build_check.cpp
new file mode 100644
index 0000000..8ec94f5
--- /dev/null
+++ b/native/jni/src/gesture/build_check.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#include "gesture_decoder.h"
+
+namespace latinime {
+};
+// namespace latinime
diff --git a/native/jni/src/gesture/gesture_decoder.h b/native/jni/src/gesture/gesture_decoder.h
new file mode 100644
index 0000000..8e79555
--- /dev/null
+++ b/native/jni/src/gesture/gesture_decoder.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_GESTURE_DECODER_H
+#define LATINIME_GESTURE_DECODER_H
+
+#include "defines.h"
+#include "gesture_decoder_impl.h"
+
+namespace latinime {
+
+class GestureDecoder : public GestureDecoderImpl {
+
+ public:
+    GestureDecoder(int maxWordLength, int maxWords) :
+            GestureDecoderImpl(maxWordLength, maxWords) {
+    }
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(GestureDecoder);
+};
+} // namespace latinime
+
+#endif // LATINIME_INCREMENTAL_DECODER_H
diff --git a/native/jni/src/gesture/gesture_decoder_impl.h b/native/jni/src/gesture/gesture_decoder_impl.h
new file mode 100644
index 0000000..be4e8b3
--- /dev/null
+++ b/native/jni/src/gesture/gesture_decoder_impl.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_GESTURE_DECODER_IMPL_H
+#define LATINIME_GESTURE_DECODER_IMPL_H
+
+#include "defines.h"
+#include "incremental_decoder.h"
+
+namespace latinime {
+
+class GestureDecoderImpl : public IncrementalDecoder {
+
+ public:
+    GestureDecoderImpl(int maxWordLength, int maxWords) :
+            IncrementalDecoder(maxWordLength, maxWords) {
+    }
+
+    int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times,
+            int *pointerIds, int *codes, int inputSize, int commitPoint, bool isMainDict,
+            unsigned short *outWords, int *frequencies, int *outputIndices) {
+        return 0;
+    }
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(GestureDecoderImpl);
+};
+} // namespace latinime
+
+#endif // LATINIME_GESTURE_DECODER_IMPL_H
diff --git a/native/jni/src/gesture/incremental_decoder.h b/native/jni/src/gesture/incremental_decoder.h
new file mode 100644
index 0000000..fe93552
--- /dev/null
+++ b/native/jni/src/gesture/incremental_decoder.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_INCREMENTAL_DECODER_H
+#define LATINIME_INCREMENTAL_DECODER_H
+
+#include "defines.h"
+#include "incremental_decoder_impl.h"
+
+namespace latinime {
+
+class IncrementalDecoder : public IncrementalDecoderImpl {
+
+ public:
+     IncrementalDecoder(int maxWordLength, int maxWords) :
+             IncrementalDecoderImpl(maxWordLength, maxWords) {
+     }
+
+ private:
+     DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalDecoder);
+};
+} // namespace latinime
+
+#endif // LATINIME_INCREMENTAL_DECODER_H
diff --git a/native/jni/src/gesture/incremental_decoder_impl.h b/native/jni/src/gesture/incremental_decoder_impl.h
new file mode 100644
index 0000000..5731ad8
--- /dev/null
+++ b/native/jni/src/gesture/incremental_decoder_impl.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_INCREMENTAL_DECODER_IMPL_H
+#define LATINIME_INCREMENTAL_DECODER_IMPL_H
+
+#include "bigram_dictionary.h"
+#include "defines.h"
+#include "incremental_decoder_interface.h"
+#include "unigram_dictionary.h"
+
+namespace latinime {
+
+class IncrementalDecoderImpl : IncrementalDecoderInterface {
+
+ public:
+     IncrementalDecoderImpl(int maxWordLength, int maxWords) { };
+     void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram) { };
+     void setPrevWord(const int32_t *prevWord, int prevWordLength) { };
+     void reset() { };
+
+ private:
+     DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalDecoderImpl);
+};
+} // namespace latinime
+
+#endif // LATINIME_INCREMENTAL_DECODER_IMPL_H
diff --git a/native/jni/src/gesture/incremental_decoder_interface.h b/native/jni/src/gesture/incremental_decoder_interface.h
new file mode 100644
index 0000000..d34b0da
--- /dev/null
+++ b/native/jni/src/gesture/incremental_decoder_interface.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_INCREMENTAL_DECODER_INTERFACE_H
+#define LATINIME_INCREMENTAL_DECODER_INTERFACE_H
+
+#include "bigram_dictionary.h"
+#include "defines.h"
+#include "proximity_info.h"
+#include "unigram_dictionary.h"
+
+namespace latinime {
+
+class IncrementalDecoderInterface {
+
+ public:
+    virtual int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times,
+            int *pointerIds, int *codes, int inputSize, int commitPoint, bool isMainDict,
+            unsigned short *outWords, int *frequencies, int *outputIndices) = 0;
+    virtual void reset() = 0;
+    virtual void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram) = 0;
+    virtual void setPrevWord(const int32_t *prevWord, int prevWordLength) = 0;
+    virtual ~IncrementalDecoderInterface() { };
+};
+} // namespace latinime
+
+#endif // LATINIME_INCREMENTAL_DECODER_INTERFACE_H