Merge "Fix UserHistoryDictIOUtilsTests by adding @UsedForTesting."
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 95c9bca..8fdff8f 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -33,6 +33,7 @@
  * be searched for suggestions and valid words.
  */
 // TODO: Remove after binary dictionary supports dynamic update.
+@UsedForTesting
 public class ExpandableDictionary extends Dictionary {
     private static final String TAG = ExpandableDictionary.class.getSimpleName();
     /**
@@ -146,6 +147,7 @@
 
     private int[][] mCodes;
 
+    @UsedForTesting
     public ExpandableDictionary(final String dictType) {
         super(dictType);
         clearDictionary();
@@ -164,6 +166,7 @@
      * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored
      *   if shortcutTarget is null.
      */
+    @UsedForTesting
     public void addWord(final String word, final String shortcutTarget, final int frequency,
             final int shortcutFreq) {
         if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 2e22af9..9936b3e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -3276,6 +3276,8 @@
 
         final Printer p = new PrintWriterPrinter(fout);
         p.println("LatinIME state :");
+        p.println("  VersionCode = " + ApplicationUtils.getVersionCode(this));
+        p.println("  VersionName = " + ApplicationUtils.getVersionName(this));
         final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
         final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
         p.println("  Keyboard mode = " + keyboardMode);
diff --git a/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java b/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java
index 08a2a8c..e521ec8 100644
--- a/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java
@@ -62,4 +62,22 @@
         }
         return "";
     }
+
+    /**
+     * A utility method to get the application's PackageInfo.versionCode
+     * @return the application's PackageInfo.versionCode
+     */
+    public static int getVersionCode(final Context context) {
+        try {
+            if (context == null) {
+                return 0;
+            }
+            final String packageName = context.getPackageName();
+            final PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+            return info.versionCode;
+        } catch (final NameNotFoundException e) {
+            Log.e(TAG, "Could not find version info.", e);
+        }
+        return 0;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
index 1992b2f..677035e 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
@@ -20,6 +20,9 @@
 
 import java.util.concurrent.TimeUnit;
 
+import com.android.inputmethod.annotations.UsedForTesting;
+
+@UsedForTesting
 public final class UserHistoryForgettingCurveUtils {
     private static final String TAG = UserHistoryForgettingCurveUtils.class.getSimpleName();
     private static final boolean DEBUG = false;
@@ -118,18 +121,22 @@
         }
     }
 
+    @UsedForTesting
     /* package */ static  int fcToElapsedTime(byte fc) {
         return fc & 0x0F;
     }
 
+    @UsedForTesting
     /* package */ static int fcToCount(byte fc) {
         return (fc >> 4) & 0x03;
     }
 
+    @UsedForTesting
     /* package */ static int fcToLevel(byte fc) {
         return (fc >> 6) & 0x03;
     }
 
+    @UsedForTesting
     private static int calcFreq(int elapsedTime, int count, int level) {
         if (level <= 0) {
             // Reserved words, just return -1
@@ -158,6 +165,7 @@
         return calcFreq(elapsedTime, count, level);
     }
 
+    @UsedForTesting
     public static byte pushElapsedTime(byte fc) {
         int elapsedTime = fcToElapsedTime(fc);
         int count = fcToCount(fc);
@@ -173,6 +181,7 @@
         return calcFc(elapsedTime, count, level);
     }
 
+    @UsedForTesting
     public static byte pushCount(byte fc, boolean isValid) {
         final int elapsedTime = fcToElapsedTime(fc);
         int count = fcToCount(fc);
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 55a5c06..f4c8f7a 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -87,7 +87,8 @@
         dynamic_patricia_trie_writing_utils.cpp) \
     $(addprefix suggest/policyimpl/dictionary/structure/v4/, \
         ver4_dict_constants.cpp \
-        ver4_patricia_trie_policy.cpp) \
+        ver4_patricia_trie_policy.cpp \
+        ver4_patricia_trie_reading_utils.cpp ) \
     $(addprefix suggest/policyimpl/dictionary/utils/, \
         buffer_with_extendable_buffer.cpp \
         byte_array_utils.cpp \
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h
new file mode 100644
index 0000000..daaf08f
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013, 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_PROBABILITY_DICT_CONTENT_H
+#define LATINIME_PROBABILITY_DICT_CONTENT_H
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+class ProbabilityDictContent : public SingleDictContent {
+ public:
+    ProbabilityDictContent(const char *const dictDirPath, const bool isUpdatable)
+            : SingleDictContent(dictDirPath, Ver4DictConstants::FREQ_FILE_EXTENSION,
+                    isUpdatable) {}
+
+    int getProbability(const int terminalId) const {
+        if (terminalId < 0 || terminalId >= getSize()) {
+            return NOT_A_PROBABILITY;
+        }
+        return Ver4PatriciaTrieReadingUtils::getProbability(getBuffer(), terminalId);
+    }
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(ProbabilityDictContent);
+
+    int getSize() const {
+        return getBuffer()->getTailPosition() / (Ver4DictConstants::PROBABILITY_SIZE
+                + Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE);
+    }
+};
+} // namespace latinime
+#endif /* LATINIME_PROBABILITY_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
index e415881..4cb96da 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
@@ -39,6 +39,15 @@
         return mMmappedBuffer.get() != 0;
     }
 
+ protected:
+    BufferWithExtendableBuffer *getWritableBuffer() {
+        return &mExpandableContentBuffer;
+    }
+
+    const BufferWithExtendableBuffer *getBuffer() const {
+        return &mExpandableContentBuffer;
+    }
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(SingleDictContent);
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
index 1164c40..333a7c2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
@@ -18,6 +18,7 @@
 #define LATINIME_VER4_DICT_BUFFER_H
 
 #include "defines.h"
+#include "suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h"
 #include "suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h"
 #include "suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
@@ -42,10 +43,18 @@
                 && mShortcutDictContent.isValid();
     }
 
-    AK_FORCE_INLINE const uint8_t *getRawDictBuffer() const {
+    AK_FORCE_INLINE uint8_t *getRawDictBuffer() const {
         return mDictBuffer.get()->getBuffer();
     }
 
+    AK_FORCE_INLINE int getRawDictBufferSize() const {
+        return mDictBuffer.get()->getBufferSize();
+    }
+
+    AK_FORCE_INLINE const ProbabilityDictContent *getProbabilityDictContent() const {
+        return &mProbabilityDictContent;
+    }
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4DictBuffers);
 
@@ -54,8 +63,7 @@
             : mDictBuffer(dictBuffer),
               mTerminalAddressTable(dictDirPath,
                       Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION, isUpdatable),
-              mProbabilityDictContent(dictDirPath, Ver4DictConstants::FREQ_FILE_EXTENSION,
-                      isUpdatable),
+              mProbabilityDictContent(dictDirPath, isUpdatable),
               mBigramDictContent(dictDirPath,
                       Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION,
                       Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION,
@@ -67,7 +75,7 @@
 
     const MmappedBuffer::MmappedBufferPtr mDictBuffer;
     SingleDictContent mTerminalAddressTable;
-    SingleDictContent mProbabilityDictContent;
+    ProbabilityDictContent mProbabilityDictContent;
     SparseTableDictContent mBigramDictContent;
     SparseTableDictContent mShortcutDictContent;
 };
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
index 0bfd07b..160259a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
@@ -31,5 +31,7 @@
         ".shortcut_index_shortcut";
 
 const int Ver4DictConstants::NOT_A_TERMINAL = -1;
+const int Ver4DictConstants::PROBABILITY_SIZE = 1;
+const int Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE = 1;
 
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
index 6498ce4..dcc36d1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
@@ -35,6 +35,8 @@
     static const char *const SHORTCUT_CONTENT_TABLE_FILE_EXTENSION;
 
     static const int NOT_A_TERMINAL;
+    static const int PROBABILITY_SIZE;
+    static const int FLAGS_IN_PROBABILITY_FILE_SIZE;
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4DictConstants);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp
new file mode 100644
index 0000000..3304f15
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013, 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 "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h"
+
+#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+/* static */ int Ver4PatriciaTrieReadingUtils::getProbability(
+        const BufferWithExtendableBuffer *const probabilityBuffer, const int terminalId) {
+    int pos = terminalId * (Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE
+            + Ver4DictConstants::PROBABILITY_SIZE)
+                    + Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE;
+    return probabilityBuffer->readUintAndAdvancePosition(Ver4DictConstants::PROBABILITY_SIZE, &pos);
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h
new file mode 100644
index 0000000..ee369d1
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013, 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_VER4_PATRICIA_TRIE_READING_UTILS_H
+#define LATINIME_VER4_PATRICIA_TRIE_READING_UTILS_H
+
+#include <stdint.h>
+
+#include "defines.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+
+class Ver4PatriciaTrieReadingUtils {
+ public:
+    static int getProbability(const BufferWithExtendableBuffer *const probabilityBuffer,
+            const int terminalId);
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTrieReadingUtils);
+};
+} // namespace latinime
+#endif /* LATINIME_VER4_PATRICIA_TRIE_READING_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
index 5032131..e028de5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
@@ -23,6 +23,20 @@
 // TODO: Needs to allocate larger memory corresponding to the current vector size.
 const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 128 * 1024;
 
+uint32_t BufferWithExtendableBuffer::readUintAndAdvancePosition(const int size,
+        int *const pos) const {
+    const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(*pos);
+    if (readingPosIsInAdditionalBuffer) {
+        *pos -= mOriginalBufferSize;
+    }
+    const int value = ByteArrayUtils::readUintAndAdvancePosition(
+            getBuffer(readingPosIsInAdditionalBuffer), size, pos);
+    if (readingPosIsInAdditionalBuffer) {
+        *pos += mOriginalBufferSize;
+    }
+    return value;
+}
+
 bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data, const int size,
         int *const pos) {
     if (!(size >= 1 && size <= 4)) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
index 1e27a1b..2d89f71 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
@@ -71,6 +71,8 @@
         }
     }
 
+    uint32_t readUintAndAdvancePosition(const int size, int *const pos) const;
+
     AK_FORCE_INLINE int getOriginalBufferSize() const {
         return mOriginalBufferSize;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
index 0c15768..1ca01b8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
@@ -114,6 +114,24 @@
         return buffer[(*pos)++];
     }
 
+    static AK_FORCE_INLINE int readUintAndAdvancePosition(const uint8_t *const buffer,
+            const int size, int *const pos) {
+        // size must be in 1 to 4.
+        ASSERT(size >= 1 && size <= 4);
+        switch (size) {
+            case 1:
+                return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+            case 2:
+                return ByteArrayUtils::readUint16AndAdvancePosition(buffer, pos);
+            case 3:
+                return ByteArrayUtils::readUint24AndAdvancePosition(buffer, pos);
+            case 4:
+                return ByteArrayUtils::readUint32AndAdvancePosition(buffer, pos);
+            default:
+                return 0;
+        }
+    }
+
     /**
      * Code Point Reading
      *