Merge "Fix space key on tablet symbols/symbols shifted"
diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java
index a4a17e1..ed487e1 100644
--- a/java/src/com/android/inputmethod/event/Event.java
+++ b/java/src/com/android/inputmethod/event/Event.java
@@ -120,6 +120,34 @@
                 FLAG_DEAD, next);
     }
 
+    /**
+     * Create an input event with nothing but a code point. This is the most basic possible input
+     * event; it contains no information on many things the IME requires to function correctly,
+     * so avoid using it unless really nothing is known about this input.
+     * @param codePoint the code point.
+     * @return an event for this code point.
+     */
+    public static Event createEventForCodePointFromUnknownSource(final int codePoint) {
+        // TODO: should we have a different type of event for this? After all, it's not a key press.
+        return new Event(EVENT_INPUT_KEYPRESS, codePoint, NOT_A_KEY_CODE,
+                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, FLAG_NONE, null /* next */);
+    }
+
+    /**
+     * Creates an input event with a code point and x, y coordinates. This is typically used when
+     * resuming a previously-typed word, when the coordinates are still known.
+     * @param codePoint the code point to input.
+     * @param x the X coordinate.
+     * @param y the Y coordinate.
+     * @return an event for this code point and coordinates.
+     */
+    public static Event createEventForCodePointFromAlreadyTypedText(final int codePoint,
+            final int x, final int y) {
+        // TODO: should we have a different type of event for this? After all, it's not a key press.
+        return new Event(EVENT_INPUT_KEYPRESS, codePoint, NOT_A_KEY_CODE, x, y, FLAG_NONE,
+                null /* next */);
+    }
+
     public static Event createNotHandledEvent() {
         return new Event(EVENT_NOT_HANDLED, NOT_A_CODE_POINT, NOT_A_KEY_CODE,
                 Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, FLAG_NONE, null);
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java
index 8546ceb..2a16ab5 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -18,6 +18,10 @@
 
 import android.text.TextUtils;
 
+import com.android.inputmethod.event.Event;
+
+import java.util.ArrayList;
+
 /**
  * This class encapsulates data about a word previously composed, but that has been
  * committed already. This is used for resuming suggestion, and cancel auto-correction.
@@ -41,6 +45,7 @@
     public static final String NOT_A_SEPARATOR = "";
 
     public final int[] mPrimaryKeyCodes;
+    public final ArrayList<Event> mEvents;
     public final String mTypedWord;
     public final CharSequence mCommittedWord;
     public final String mSeparatorString;
@@ -52,19 +57,21 @@
     private boolean mActive;
 
     public static final LastComposedWord NOT_A_COMPOSED_WORD =
-            new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null,
-            WordComposer.CAPS_MODE_OFF);
+            new LastComposedWord(null, new ArrayList<Event>(), null, "", "",
+            NOT_A_SEPARATOR, null, WordComposer.CAPS_MODE_OFF);
 
     // Warning: this is using the passed objects as is and fully expects them to be
     // immutable. Do not fiddle with their contents after you passed them to this constructor.
-    public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers,
-            final String typedWord, final CharSequence committedWord, final String separatorString,
+    public LastComposedWord(final int[] primaryKeyCodes, final ArrayList<Event> events,
+            final InputPointers inputPointers, final String typedWord,
+            final CharSequence committedWord, final String separatorString,
             final String prevWord, final int capitalizedMode) {
         mPrimaryKeyCodes = primaryKeyCodes;
         if (inputPointers != null) {
             mInputPointers.copy(inputPointers);
         }
         mTypedWord = typedWord;
+        mEvents = new ArrayList<Event>(events);
         mCommittedWord = committedWord;
         mSeparatorString = separatorString;
         mActive = true;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 1259769..2ac11aa 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,10 +16,14 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.event.Event;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
 import com.android.inputmethod.latin.utils.StringUtils;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 
 /**
  * A place to store the currently composing word with information such as adjacent key codes as well
@@ -41,6 +45,8 @@
     // and mCodePointSize can go past that. If mCodePointSize is greater than MAX_WORD_LENGTH,
     // this just does not contain the associated code points past MAX_WORD_LENGTH.
     private int[] mPrimaryKeyCodes;
+    // The list of events that served to compose this string.
+    private final ArrayList<Event> mEvents;
     private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH);
     // This is the typed word, as a StringBuilder. This has the same contents as mPrimaryKeyCodes
     // but under a StringBuilder representation for ease of use, depending on what is more useful
@@ -82,6 +88,7 @@
 
     public WordComposer() {
         mPrimaryKeyCodes = new int[MAX_WORD_LENGTH];
+        mEvents = CollectionUtils.newArrayList();
         mTypedWord = new StringBuilder(MAX_WORD_LENGTH);
         mAutoCorrection = null;
         mTrailingSingleQuotesCount = 0;
@@ -95,6 +102,7 @@
 
     public WordComposer(final WordComposer source) {
         mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length);
+        mEvents = new ArrayList<Event>(source.mEvents);
         mTypedWord = new StringBuilder(source.mTypedWord);
         mInputPointers.copy(source.mInputPointers);
         mCapsCount = source.mCapsCount;
@@ -115,6 +123,7 @@
      */
     public void reset() {
         mTypedWord.setLength(0);
+        mEvents.clear();
         mAutoCorrection = null;
         mCapsCount = 0;
         mDigitsCount = 0;
@@ -170,11 +179,16 @@
     }
 
     /**
-     * Add a new keystroke, with the pressed key's code point with the touch point coordinates.
+     * Add a new event for a key stroke, with the pressed key's code point with the touch point
+     * coordinates.
      */
-    public void add(final int primaryCode, final int keyX, final int keyY) {
+    public void add(final Event event) {
+        final int primaryCode = event.mCodePoint;
+        final int keyX = event.mX;
+        final int keyY = event.mY;
         final int newIndex = size();
         mTypedWord.appendCodePoint(primaryCode);
+        mEvents.add(event);
         refreshSize();
         mCursorPositionWithinWord = mCodePointSize;
         if (newIndex < MAX_WORD_LENGTH) {
@@ -202,6 +216,7 @@
 
     public void setCursorPositionWithinWord(final int posWithinWord) {
         mCursorPositionWithinWord = posWithinWord;
+        // TODO: compute where that puts us inside the events
     }
 
     public boolean isCursorFrontOrMiddleOfComposingWord() {
@@ -268,7 +283,7 @@
             final int codePoint = Character.codePointAt(word, i);
             // We don't want to override the batch input points that are held in mInputPointers
             // (See {@link #add(int,int,int)}).
-            add(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+            add(Event.createEventForCodePointFromUnknownSource(codePoint));
         }
     }
 
@@ -285,8 +300,9 @@
         reset();
         final int length = codePoints.length;
         for (int i = 0; i < length; ++i) {
-            add(codePoints[i], CoordinateUtils.xFromArray(coordinates, i),
-                    CoordinateUtils.yFromArray(coordinates, i));
+            add(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i],
+                    CoordinateUtils.xFromArray(coordinates, i),
+                    CoordinateUtils.yFromArray(coordinates, i)));
         }
         mIsResumed = true;
         mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString();
@@ -305,6 +321,8 @@
                         "In WordComposer: mCodes and mTypedWords have non-matching lengths");
             }
             final int lastChar = mTypedWord.codePointBefore(stringBuilderLength);
+            // TODO: with events and composition, this is absolutely not necessarily true.
+            mEvents.remove(mEvents.size() - 1);
             if (Character.isSupplementaryCodePoint(lastChar)) {
                 mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength);
             } else {
@@ -445,7 +463,7 @@
         // the last composed word to ensure this does not happen.
         final int[] primaryKeyCodes = mPrimaryKeyCodes;
         mPrimaryKeyCodes = new int[MAX_WORD_LENGTH];
-        final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes,
+        final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, mEvents,
                 mInputPointers, mTypedWord.toString(), committedWord, separatorString,
                 prevWord, mCapitalizedMode);
         mInputPointers.reset();
@@ -458,6 +476,7 @@
         mIsBatchMode = false;
         mPreviousWordForSuggestion = committedWord.toString();
         mTypedWord.setLength(0);
+        mEvents.clear();
         mCodePointSize = 0;
         mTrailingSingleQuotesCount = 0;
         mIsFirstCharCapitalized = false;
@@ -480,6 +499,8 @@
     public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord,
             final String previousWord) {
         mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes;
+        mEvents.clear();
+        Collections.copy(mEvents, lastComposedWord.mEvents);
         mInputPointers.set(lastComposedWord.mInputPointers);
         mTypedWord.setLength(0);
         mTypedWord.append(lastComposedWord.mTypedWord);
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index cc5611b..cb55aa0 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -730,8 +730,7 @@
             resetComposingState(false /* alsoResetLastComposedWord */);
         }
         if (isComposingWord) {
-            // TODO: pass the entire event to the word composer.
-            mWordComposer.add(codePoint, inputTransaction.mEvent.mX, inputTransaction.mEvent.mY);
+            mWordComposer.add(inputTransaction.mEvent);
             // If it's the first letter, make note of auto-caps state
             if (mWordComposer.size() == 1) {
                 // We pass 1 to getPreviousWordForSuggestion because we were not composing a word
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
index ecc9fda..6ed65d9 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
@@ -47,11 +47,11 @@
 
 const int HeaderPolicy::DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE = 100;
 const float HeaderPolicy::MULTIPLE_WORD_COST_MULTIPLIER_SCALE = 100.0f;
-const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP = 4;
-const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID = 0;
-// 4 days
+const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP = 2;
+const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID = 3;
+// 30 days
 const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS =
-        4 * 24 * 60 * 60;
+        30 * 24 * 60 * 60;
 
 const int HeaderPolicy::DEFAULT_MAX_UNIGRAM_COUNT = 10000;
 const int HeaderPolicy::DEFAULT_MAX_BIGRAM_COUNT = 10000;
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
index 69420d6..918f090 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
@@ -75,16 +75,16 @@
     }
 
     private void forcePassingShortTime(final BinaryDictionary binaryDictionary) {
-        // 4 days.
-        final int timeToElapse = (int)TimeUnit.SECONDS.convert(4, TimeUnit.DAYS);
+        // 30 days.
+        final int timeToElapse = (int)TimeUnit.SECONDS.convert(30, TimeUnit.DAYS);
         mCurrentTime += timeToElapse;
         setCurrentTimeForTestMode(mCurrentTime);
         binaryDictionary.flushWithGC();
     }
 
     private void forcePassingLongTime(final BinaryDictionary binaryDictionary) {
-        // 60 days.
-        final int timeToElapse = (int)TimeUnit.SECONDS.convert(60, TimeUnit.DAYS);
+        // 365 days.
+        final int timeToElapse = (int)TimeUnit.SECONDS.convert(365, TimeUnit.DAYS);
         mCurrentTime += timeToElapse;
         setCurrentTimeForTestMode(mCurrentTime);
         binaryDictionary.flushWithGC();
@@ -210,9 +210,6 @@
         addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY);
         assertFalse(binaryDictionary.isValidWord("a"));
         addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY);
-        assertFalse(binaryDictionary.isValidWord("a"));
-        addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY);
-        assertFalse(binaryDictionary.isValidWord("a"));
         addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY);
         assertTrue(binaryDictionary.isValidWord("a"));
 
@@ -222,10 +219,6 @@
         addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY);
         assertFalse(binaryDictionary.isValidBigram("a", "b"));
         addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY);
-        assertFalse(binaryDictionary.isValidBigram("a", "b"));
-        addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY);
-        assertFalse(binaryDictionary.isValidBigram("a", "b"));
-        addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY);
         assertTrue(binaryDictionary.isValidBigram("a", "b"));
 
         addUnigramWord(binaryDictionary, "c", DUMMY_PROBABILITY);
@@ -265,8 +258,6 @@
         addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
         addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
         addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
-        addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
-        addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
         assertTrue(binaryDictionary.isValidWord("a"));
         forcePassingShortTime(binaryDictionary);
         assertTrue(binaryDictionary.isValidWord("a"));
@@ -289,12 +280,6 @@
         addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
         addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY);
         addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY);
-        addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
-        addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY);
-        addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY);
-        addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY);
-        addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY);
-        addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY);
         assertTrue(binaryDictionary.isValidBigram("a", "b"));
         forcePassingShortTime(binaryDictionary);
         assertTrue(binaryDictionary.isValidBigram("a", "b"));
@@ -370,7 +355,7 @@
 
     private void testOverflowUnigrams(final int formatVersion) {
         final int unigramCount = 20000;
-        final int eachUnigramTypedCount = 5;
+        final int eachUnigramTypedCount = 2;
         final int strongUnigramTypedCount = 20;
         final int weakUnigramTypedCount = 1;
         final int codePointSetSize = 50;
@@ -505,7 +490,7 @@
         final int bigramCount = 20000;
         final int unigramCount = 1000;
         final int unigramTypedCount = 20;
-        final int eachBigramTypedCount = 5;
+        final int eachBigramTypedCount = 2;
         final int strongBigramTypedCount = 20;
         final int weakBigramTypedCount = 1;
         final int codePointSetSize = 50;
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
index 4d44135..b476627 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -948,16 +948,15 @@
             final HashSet<String> bigramWord1s = bigrams.get(word0);
             final WordProperty wordProperty = binaryDictionary.getWordProperty(word0);
             assertEquals(bigramWord1s.size(), wordProperty.mBigrams.size());
-            final int unigramProbability = wordProperty.getProbability();
             for (int j = 0; j < wordProperty.mBigrams.size(); j++) {
                 final String word1 = wordProperty.mBigrams.get(j).mWord;
                 assertTrue(bigramWord1s.contains(word1));
-                final int bigramProbability = wordProperty.mBigrams.get(j).getProbability();
-                final int probability = binaryDictionary.calculateProbability(
-                        unigramProbability, bigramProbability);
-                assertEquals((int)bigramProbabilities.get(new Pair<String, String>(word0, word1)),
-                        probability);
-                assertEquals(wordProperty.mBigrams.get(j).getProbability(), probability);
+                final int bigramProbabilityDelta = bigramProbabilities.get(
+                        new Pair<String, String>(word0, word1));
+                final int unigramProbability = wordProbabilities.get(word1);
+                final int bigramProbablity = binaryDictionary.calculateProbability(
+                        unigramProbability, bigramProbabilityDelta);
+                assertEquals(wordProperty.mBigrams.get(j).getProbability(), bigramProbablity);
             }
         }
     }
@@ -1040,16 +1039,16 @@
             assertEquals((int)wordProbabilitiesToCheckLater.get(word0),
                     wordProperty.mProbabilityInfo.mProbability);
             wordSet.remove(word0);
-            final int unigramProbability = wordProperty.getProbability();
             final HashSet<String> bigramWord1s = bigrams.get(word0);
             for (int j = 0; j < wordProperty.mBigrams.size(); j++) {
                 final String word1 = wordProperty.mBigrams.get(j).mWord;
                 assertTrue(bigramWord1s.contains(word1));
-                final int bigramProbability = wordProperty.mBigrams.get(j).getProbability();
-                final int probability = binaryDictionary.calculateProbability(
-                        unigramProbability, bigramProbability);
+                final int unigramProbability = wordProbabilitiesToCheckLater.get(word1);
                 final Pair<String, String> bigram = new Pair<String, String>(word0, word1);
-                assertEquals((int)bigramProbabilitiesToCheckLater.get(bigram), probability);
+                final int bigramProbabilityDelta = bigramProbabilitiesToCheckLater.get(bigram);
+                final int bigramProbablity = binaryDictionary.calculateProbability(
+                        unigramProbability, bigramProbabilityDelta);
+                assertEquals(wordProperty.mBigrams.get(j).getProbability(), bigramProbablity);
                 bigramSet.remove(bigram);
             }
             token = result.mNextToken;
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index ab97513..ab62456 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -356,7 +356,7 @@
         final String NOT_CORRECTED_RESULT = "qpmx ";
         final String DESIRED_WORD = "qpmz";
         final String CORRECTED_RESULT = "qpmz ";
-        final int typeCountNotToAutocorrect = 3;
+        final int typeCountNotToAutocorrect = 1;
         final int typeCountToAutoCorrect = 16;
         int startIndex = 0;
         int endIndex = 0;
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index 04840d6..60599f6 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -72,8 +72,8 @@
     }
 
     private void forcePassingLongTime() {
-        // 60 days.
-        final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(60);
+        // 365 days.
+        final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(365);
         mCurrentTime += timeToElapse;
         setCurrentTimeForTestMode(mCurrentTime);
     }
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index c0a5562..948c03b 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -29,32 +29,34 @@
 LATINIME_LOCAL_DIR := ../..
 LATINIME_BASE_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/java/src/com/android/inputmethod
 LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annotations
-LATINIME_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin
-MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_CORE_SOURCE_DIRECTORY)/makedict
+MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/makedict
 
 # 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.
-USED_TARGETTED_UTILS := \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/BinaryDictionary.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/DicTraverseSession.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/Dictionary.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/InputPointers.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/LastComposedWord.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/LatinImeLogger.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/SuggestedWords.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/WordComposer.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/settings/NativeSuggestOptions.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/BinaryDictionaryUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayDictBuffer.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CombinedFormatUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CoordinateUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/FileUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/JniUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/LocaleUtils.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ResizableIntArray.java \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/StringUtils.java
+LATINIME_SRCS_FOR_DICTTOOL := \
+        event/Event.java \
+        latin/BinaryDictionary.java \
+        latin/DicTraverseSession.java \
+        latin/Dictionary.java \
+        latin/InputPointers.java \
+        latin/LastComposedWord.java \
+        latin/LatinImeLogger.java \
+        latin/SuggestedWords.java \
+        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 \
+        latin/utils/FileUtils.java \
+        latin/utils/JniUtils.java \
+        latin/utils/LocaleUtils.java \
+        latin/utils/ResizableIntArray.java \
+        latin/utils/StringUtils.java
+USED_TARGETED_SRCS := $(addprefix $(LATINIME_BASE_SOURCE_DIRECTORY)/, \
+        $(LATINIME_SRCS_FOR_DICTTOOL))
 
 DICTTOOL_ONDEVICE_TESTS_DIRECTORY := \
         $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin/makedict/
@@ -68,11 +70,11 @@
 LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \
         $(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \
         $(LOCAL_ANNOTATIONS_SRC_FILES) \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/Constants.java \
+        $(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_TARGETTED_UTILS)
+        $(USED_TARGETED_SRCS)
 
 LOCAL_JAVA_LIBRARIES := junit
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LATINIME_HOST_NATIVE_LIBNAME)