Separate TimeKeeper from ForgettingCurveUtils.

Bug: 11073222
Change-Id: I6c27156edc01186f4e2a958283a45a62dbb2c113
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 3c8b856..52ac333 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -117,7 +117,8 @@
     $(addprefix utils/, \
         autocorrection_threshold_utils.cpp \
         char_utils.cpp \
-        log_utils.cpp)
+        log_utils.cpp \
+        time_keeper.cpp)
 
 LOCAL_SRC_FILES := \
     $(LATIN_IME_JNI_SRC_FILES) \
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index f62d06b..aecf991 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -28,6 +28,7 @@
 #include "suggest/policyimpl/gesture/gesture_suggest_policy_factory.h"
 #include "suggest/policyimpl/typing/typing_suggest_policy_factory.h"
 #include "utils/log_utils.h"
+#include "utils/time_keeper.h"
 
 namespace latinime {
 
@@ -47,6 +48,7 @@
         int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint,
         const SuggestOptions *const suggestOptions, int *outWords, int *frequencies,
         int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const {
+    TimeKeeper::setCurrentTime();
     int result = 0;
     if (suggestOptions->isGesture()) {
         DicTraverseSession::initSessionInstance(
@@ -74,12 +76,14 @@
 
 int Dictionary::getBigrams(const int *word, int length, int *outWords, int *frequencies,
         int *outputTypes) const {
+    TimeKeeper::setCurrentTime();
     if (length <= 0) return 0;
     return mBigramDictionary.get()->getPredictions(word, length, outWords, frequencies,
             outputTypes);
 }
 
 int Dictionary::getProbability(const int *word, int length) const {
+    TimeKeeper::setCurrentTime();
     int pos = getDictionaryStructurePolicy()->getTerminalPtNodePositionOfWord(word, length,
             false /* forceLowerCaseSearch */);
     if (NOT_A_DICT_POS == pos) {
@@ -90,40 +94,48 @@
 
 int Dictionary::getBigramProbability(const int *word0, int length0, const int *word1,
         int length1) const {
+    TimeKeeper::setCurrentTime();
     return mBigramDictionary.get()->getBigramProbability(word0, length0, word1, length1);
 }
 
 void Dictionary::addUnigramWord(const int *const word, const int length, const int probability,
         const int timestamp) {
+    TimeKeeper::setCurrentTime();
     mDictionaryStructureWithBufferPolicy.get()->addUnigramWord(word, length, probability,
             timestamp);
 }
 
 void Dictionary::addBigramWords(const int *const word0, const int length0, const int *const word1,
         const int length1, const int probability, const int timestamp) {
+    TimeKeeper::setCurrentTime();
     mDictionaryStructureWithBufferPolicy.get()->addBigramWords(word0, length0, word1, length1,
             probability, timestamp);
 }
 
 void Dictionary::removeBigramWords(const int *const word0, const int length0,
         const int *const word1, const int length1) {
+    TimeKeeper::setCurrentTime();
     mDictionaryStructureWithBufferPolicy.get()->removeBigramWords(word0, length0, word1, length1);
 }
 
 void Dictionary::flush(const char *const filePath) {
+    TimeKeeper::setCurrentTime();
     mDictionaryStructureWithBufferPolicy.get()->flush(filePath);
 }
 
 void Dictionary::flushWithGC(const char *const filePath) {
+    TimeKeeper::setCurrentTime();
     mDictionaryStructureWithBufferPolicy.get()->flushWithGC(filePath);
 }
 
 bool Dictionary::needsToRunGC(const bool mindsBlockByGC) {
+    TimeKeeper::setCurrentTime();
     return mDictionaryStructureWithBufferPolicy.get()->needsToRunGC(mindsBlockByGC);
 }
 
 void Dictionary::getProperty(const char *const query, const int queryLength, char *const outResult,
         const int maxResultLength) {
+    TimeKeeper::setCurrentTime();
     return mDictionaryStructureWithBufferPolicy.get()->getProperty(query, queryLength, outResult,
             maxResultLength);
 }
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 d01e7a7..133ae9f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
@@ -92,12 +92,12 @@
     if (updatesLastUpdatedTime) {
         // Set current time as a last updated time.
         HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, LAST_UPDATED_TIME_KEY,
-                time(0));
+                TimeKeeper::peekCurrentTime());
     }
     if (updatesLastDecayedTime) {
         // Set current time as a last updated time.
         HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, LAST_DECAYED_TIME_KEY,
-                time(0));
+                TimeKeeper::peekCurrentTime());
     }
     if (!HeaderReadWriteUtils::writeHeaderAttributes(bufferToWrite, &attributeMapTowrite,
             &writingPos)) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
index 4c4e43b..fa5d5fa 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -17,13 +17,13 @@
 #ifndef LATINIME_HEADER_POLICY_H
 #define LATINIME_HEADER_POLICY_H
 
-#include <ctime>
 #include <stdint.h>
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_header_structure_policy.h"
 #include "suggest/policyimpl/dictionary/header/header_read_write_utils.h"
 #include "suggest/policyimpl/dictionary/utils/format_utils.h"
+#include "utils/time_keeper.h"
 
 namespace latinime {
 
@@ -39,9 +39,9 @@
               mIsDecayingDict(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap,
                       IS_DECAYING_DICT_KEY, false /* defaultValue */)),
               mLastUpdatedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
-                      LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)),
+                      LAST_UPDATED_TIME_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)),
               mLastDecayedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
-                      LAST_DECAYED_TIME_KEY, time(0) /* defaultValue */)),
+                      LAST_DECAYED_TIME_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)),
               mUnigramCount(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
                       UNIGRAM_COUNT_KEY, 0 /* defaultValue */)),
               mBigramCount(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
@@ -61,9 +61,9 @@
               mIsDecayingDict(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap,
                       IS_DECAYING_DICT_KEY, false /* defaultValue */)),
               mLastUpdatedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
-                      LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)),
+                      LAST_UPDATED_TIME_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)),
               mLastDecayedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
-                      LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)),
+                      LAST_UPDATED_TIME_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)),
               mUnigramCount(0), mBigramCount(0), mExtendedRegionSize(0),
               mHasHistoricalInfoOfWords(HeaderReadWriteUtils::readBoolAttributeValue(
                       &mAttributeMap, HAS_HISTORICAL_INFO_KEY, false /* defaultValue */)) {}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
index dd62b9c..1f38be5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
@@ -59,9 +59,6 @@
             Ver4DictBuffers::createVer4DictBuffers(headerPolicy));
     int unigramCount = 0;
     int bigramCount = 0;
-    if (needsToDecay) {
-        ForgettingCurveUtils::sTimeKeeper.setCurrentTime();
-    }
     if (!runGC(rootPtNodeArrayPos, headerPolicy, dictBuffers.get(), &unigramCount, &bigramCount,
             needsToDecay)) {
         return;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
index d959b26..ce92231 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
@@ -24,6 +24,7 @@
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/file_utils.h"
 #include "suggest/policyimpl/dictionary/utils/format_utils.h"
+#include "utils/time_keeper.h"
 
 namespace latinime {
 
@@ -31,6 +32,7 @@
 
 /* static */ bool DictFileWritingUtils::createEmptyDictFile(const char *const filePath,
         const int dictVersion, const HeaderReadWriteUtils::AttributeMap *const attributeMap) {
+    TimeKeeper::setCurrentTime();
     switch (dictVersion) {
         case 4:
             return createEmptyV4DictFile(filePath, attributeMap);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp
index 1632fd0..3ce5680 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#include <cmath>
-#include <ctime>
-#include <stdlib.h>
-
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
 
+#include <cmath>
+#include <stdlib.h>
+
 #include "suggest/core/policy/dictionary_header_structure_policy.h"
 #include "suggest/policyimpl/dictionary/utils/probability_utils.h"
+#include "utils/time_keeper.h"
 
 namespace latinime {
 
@@ -40,11 +40,6 @@
 const int ForgettingCurveUtils::DECAY_INTERVAL_SECONDS = 2 * 60 * 60;
 
 const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityTable;
-ForgettingCurveUtils::TimeKeeper ForgettingCurveUtils::sTimeKeeper;
-
-void ForgettingCurveUtils::TimeKeeper::setCurrentTime() {
-    mCurrentTime = time(0);
-}
 
 /* static */ int ForgettingCurveUtils::getProbability(const int encodedUnigramProbability,
         const int encodedBigramProbability) {
@@ -86,7 +81,7 @@
 
 /* static */ int ForgettingCurveUtils::getEncodedProbabilityToSave(const int encodedProbability,
         const DictionaryHeaderStructurePolicy *const headerPolicy) {
-    const int elapsedTime = sTimeKeeper.peekCurrentTime() - headerPolicy->getLastDecayedTime();
+    const int elapsedTime = TimeKeeper::peekCurrentTime() - headerPolicy->getLastDecayedTime();
     const int decayIterationCount = max(elapsedTime / DECAY_INTERVAL_SECONDS, 1);
     int currentEncodedProbability = max(min(encodedProbability, MAX_ENCODED_PROBABILITY), 0);
     // TODO: Implement the decay in more proper way.
@@ -116,7 +111,8 @@
     if (mindsBlockByDecay) {
         return false;
     }
-    if (headerPolicy->getLastDecayedTime() + DECAY_INTERVAL_SECONDS < time(0)) {
+    if (headerPolicy->getLastDecayedTime() + DECAY_INTERVAL_SECONDS
+            < TimeKeeper::peekCurrentTime()) {
         // Time to decay.
         return true;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h
index 2ad4238..a858719 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h
@@ -30,25 +30,11 @@
 // TODO: Quit using bigram probability to indicate the delta.
 class ForgettingCurveUtils {
  public:
-    class TimeKeeper {
-     public:
-        TimeKeeper() : mCurrentTime(0) {}
-        void setCurrentTime();
-        int peekCurrentTime() const { return mCurrentTime; };
-
-     private:
-        DISALLOW_COPY_AND_ASSIGN(TimeKeeper);
-
-        int mCurrentTime;
-    };
-
     static const int MAX_UNIGRAM_COUNT;
     static const int MAX_UNIGRAM_COUNT_AFTER_GC;
     static const int MAX_BIGRAM_COUNT;
     static const int MAX_BIGRAM_COUNT_AFTER_GC;
 
-    static TimeKeeper sTimeKeeper;
-
     static int getProbability(const int encodedUnigramProbability,
             const int encodedBigramProbability);
 
diff --git a/native/jni/src/utils/time_keeper.cpp b/native/jni/src/utils/time_keeper.cpp
new file mode 100644
index 0000000..0262840
--- /dev/null
+++ b/native/jni/src/utils/time_keeper.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "utils/time_keeper.h"
+
+#include <ctime>
+
+namespace latinime {
+
+int TimeKeeper::sCurrentTime;
+bool TimeKeeper::sSetForTesting;
+
+/* static  */ void TimeKeeper::setCurrentTime() {
+    if (!sSetForTesting) {
+        sCurrentTime = time(0);
+    }
+}
+
+/* static */ void TimeKeeper::startTestModeWithForceCurrentTime(const int currentTime) {
+    sCurrentTime = currentTime;
+    sSetForTesting = true;
+}
+
+/* static */ void TimeKeeper::stopTestMode() {
+    sSetForTesting = false;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/utils/time_keeper.h b/native/jni/src/utils/time_keeper.h
new file mode 100644
index 0000000..d066757
--- /dev/null
+++ b/native/jni/src/utils/time_keeper.h
@@ -0,0 +1,41 @@
+/*
+ * 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_TIME_KEEPER_H
+#define LATINIME_TIME_KEEPER_H
+
+#include "defines.h"
+
+namespace latinime {
+
+class TimeKeeper {
+ public:
+    static void setCurrentTime();
+
+    static void startTestModeWithForceCurrentTime(const int currentTime);
+
+    static void stopTestMode();
+
+    static int peekCurrentTime() { return sCurrentTime; };
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(TimeKeeper);
+
+    static int sCurrentTime;
+    static bool sSetForTesting;
+};
+} // namespace latinime
+#endif /* LATINIME_TIME_KEEPER_H */