diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 423c24e88d5291d4fe901ba3fed3857f8a7cf419..42275d45a2cd0706487ef02ecf22239ce5920e14 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -31,7 +31,8 @@ LOCAL_C_INCLUDES += \
     $(LATIN_IME_SRC_FULLPATH_DIR)/suggest \
     $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/dicnode \
     $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/policy \
-    $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/session
+    $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/core/session \
+    $(LATIN_IME_SRC_FULLPATH_DIR)/suggest/policyimpl/typing
 
 LOCAL_CFLAGS += -Werror -Wall -Wextra -Weffc++ -Wformat=2 -Wcast-qual -Wcast-align \
     -Wwrite-strings -Wfloat-equal -Wpointer-arith -Winit-self -Wredundant-decls -Wno-system-headers
@@ -69,6 +70,10 @@ LATIN_IME_CORE_SRC_FILES := \
     suggest/core/dicnode/dic_node_utils.cpp \
     suggest/core/policy/weighting.cpp \
     suggest/core/session/dic_traverse_session.cpp \
+    suggest/policyimpl/typing/scoring_params.cpp \
+    suggest/policyimpl/typing/typing_scoring.cpp \
+    suggest/policyimpl/typing/typing_traversal.cpp \
+    suggest/policyimpl/typing/typing_weighting.cpp \
     suggest/gesture_suggest.cpp \
     suggest/typing_suggest.cpp
 
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..90985d0fe589153650f7585319e88ea39cff8491
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "scoring_params.h"
+
+namespace latinime {
+// TODO: RENAME all
+const float ScoringParams::MAX_SPATIAL_DISTANCE = 1.0f;
+const int ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY = 40;
+const int ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED = 120;
+const float ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD = 1.0f;
+const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE = 125;
+const int ScoringParams::THRESHOLD_SHORT_WORD_LENGTH = 4;
+
+const float ScoringParams::DISTANCE_WEIGHT_LENGTH = 0.132f;
+const float ScoringParams::PROXIMITY_COST = 0.086f;
+const float ScoringParams::FIRST_PROXIMITY_COST = 0.104f;
+const float ScoringParams::OMISSION_COST = 0.388f;
+const float ScoringParams::OMISSION_COST_SAME_CHAR = 0.431f;
+const float ScoringParams::OMISSION_COST_FIRST_CHAR = 0.532f;
+const float ScoringParams::INSERTION_COST = 0.670f;
+const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.526f;
+const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.563f;
+const float ScoringParams::TRANSPOSITION_COST = 0.494f;
+const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.239f;
+const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.380f;
+const float ScoringParams::SUBSTITUTION_COST = 0.363f;
+const float ScoringParams::COST_NEW_WORD = 0.054f;
+const float ScoringParams::COST_NEW_WORD_CAPITALIZED = 0.174f;
+const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.123f;
+const float ScoringParams::COST_FIRST_LOOKAHEAD = 0.462f;
+const float ScoringParams::COST_LOOKAHEAD = 0.092f;
+const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.126f;
+const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.056f;
+const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.136f;
+const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f;
+const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f;
+const float ScoringParams::MAX_NORM_DISTANCE_FOR_EDIT = 0.1f;
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f104b3625069c208f09707d9af5fa035e5f9563
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
@@ -0,0 +1,66 @@
+/*
+ * 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_SCORING_PARAMS_H
+#define LATINIME_SCORING_PARAMS_H
+
+#include "defines.h"
+
+namespace latinime {
+
+class ScoringParams {
+ public:
+    // Fixed model parameters
+    static const float MAX_SPATIAL_DISTANCE;
+    static const int THRESHOLD_NEXT_WORD_PROBABILITY;
+    static const int THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED;
+    static const float AUTOCORRECT_OUTPUT_THRESHOLD;
+    static const int MAX_CACHE_DIC_NODE_SIZE;
+    static const int THRESHOLD_SHORT_WORD_LENGTH;
+
+    // Numerically optimized parameters (currently for tap typing only).
+    // TODO: add ability to modify these constants programmatically.
+    // TODO: explore optimization of gesture parameters.
+    static const float DISTANCE_WEIGHT_LENGTH;
+    static const float PROXIMITY_COST;
+    static const float FIRST_PROXIMITY_COST;
+    static const float OMISSION_COST;
+    static const float OMISSION_COST_SAME_CHAR;
+    static const float OMISSION_COST_FIRST_CHAR;
+    static const float INSERTION_COST;
+    static const float INSERTION_COST_SAME_CHAR;
+    static const float INSERTION_COST_FIRST_CHAR;
+    static const float TRANSPOSITION_COST;
+    static const float SPACE_SUBSTITUTION_COST;
+    static const float ADDITIONAL_PROXIMITY_COST;
+    static const float SUBSTITUTION_COST;
+    static const float COST_NEW_WORD;
+    static const float COST_NEW_WORD_CAPITALIZED;
+    static const float DISTANCE_WEIGHT_LANGUAGE;
+    static const float COST_FIRST_LOOKAHEAD;
+    static const float COST_LOOKAHEAD;
+    static const float HAS_PROXIMITY_TERMINAL_COST;
+    static const float HAS_EDIT_CORRECTION_TERMINAL_COST;
+    static const float HAS_MULTI_WORD_TERMINAL_COST;
+    static const float TYPING_BASE_OUTPUT_SCORE;
+    static const float TYPING_MAX_OUTPUT_SCORE_PER_INPUT;
+    static const float MAX_NORM_DISTANCE_FOR_EDIT;
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(ScoringParams);
+};
+} // namespace latinime
+#endif // LATINIME_SCORING_PARAMS_H
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.cpp b/native/jni/src/suggest/policyimpl/typing/typing_scoring.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..53f68f20f5cb5a4b3e9009fc61e71c87bf95310d
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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 "typing_scoring.h"
+
+namespace latinime {
+const TypingScoring TypingScoring::sInstance;
+}  // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed941f0ae9ee2f82144a4bb519970dc5dab2e194
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
@@ -0,0 +1,82 @@
+/*
+ * 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_TYPING_SCORING_H
+#define LATINIME_TYPING_SCORING_H
+
+#include "defines.h"
+#include "scoring.h"
+#include "scoring_params.h"
+
+namespace latinime {
+
+class DicNode;
+class DicTraverseSession;
+
+class TypingScoring : public Scoring {
+ public:
+    static const TypingScoring *getInstance() { return &sInstance; }
+
+    AK_FORCE_INLINE bool getMostProbableString(
+            const DicTraverseSession *const traverseSession, const int terminalSize,
+            const float languageWeight, int *const outputCodePoints, int *const type,
+            int *const freq) const {
+        return false;
+    }
+
+    AK_FORCE_INLINE void safetyNetForMostProbableString(const int terminalSize,
+            const int maxScore, int *const outputCodePoints, int *const frequencies) const {
+    }
+
+    AK_FORCE_INLINE void searchWordWithDoubleLetter(DicNode *terminals,
+            const int terminalSize, int *doubleLetterTerminalIndex,
+            DoubleLetterLevel *doubleLetterLevel) const {
+    }
+
+    AK_FORCE_INLINE float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession,
+             DicNode *const terminals, const int size) const {
+        return 1.0f;
+    }
+
+    AK_FORCE_INLINE int calculateFinalScore(const float compoundDistance,
+            const int inputSize, const bool forceCommit) const {
+        const float maxDistance = ScoringParams::DISTANCE_WEIGHT_LANGUAGE
+                + static_cast<float>(inputSize) * ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT;
+        return static_cast<int>((ScoringParams::TYPING_BASE_OUTPUT_SCORE
+                - (compoundDistance / maxDistance)
+                + (forceCommit ? ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD : 0.0f))
+                        * SUGGEST_INTERFACE_OUTPUT_SCALE);
+    }
+
+    AK_FORCE_INLINE float getDoubleLetterDemotionDistanceCost(const int terminalIndex,
+            const int doubleLetterTerminalIndex,
+            const DoubleLetterLevel doubleLetterLevel) const {
+        return 0.0f;
+    }
+
+    AK_FORCE_INLINE bool doesAutoCorrectValidWord() const {
+        return false;
+    }
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(TypingScoring);
+    static const TypingScoring sInstance;
+
+    TypingScoring() {}
+    ~TypingScoring() {}
+};
+} // namespace latinime
+#endif // LATINIME_TYPING_SCORING_H
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.h b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.h
new file mode 100644
index 0000000000000000000000000000000000000000..1f659c679694df7219060079bbfe747503894e30
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_suggest_policy.h
@@ -0,0 +1,52 @@
+/*
+ * 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_TYPING_SUGGEST_POLICY_H
+#define LATINIME_TYPING_SUGGEST_POLICY_H
+
+#include "defines.h"
+#include "suggest_policy.h"
+#include "typing_scoring.h"
+#include "typing_traversal.h"
+#include "typing_weighting.h"
+
+namespace latinime {
+
+class Scoring;
+class Traversal;
+class Weighting;
+
+class TypingSuggestPolicy : public SuggestPolicy {
+ public:
+    TypingSuggestPolicy() {}
+    virtual ~TypingSuggestPolicy() {}
+    AK_FORCE_INLINE const Traversal *getTraversal() const {
+        return TypingTraversal::getInstance();
+    }
+
+    AK_FORCE_INLINE const Scoring *getScoring() const {
+        return TypingScoring::getInstance();
+    }
+
+    AK_FORCE_INLINE const Weighting *getWeighting() const {
+        return TypingWeighting::getInstance();
+    }
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(TypingSuggestPolicy);
+};
+} // namespace latinime
+#endif // LATINIME_TYPING_SUGGEST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp b/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..68c614e77be87f02f5f5a96b68d3cea363f39892
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 "typing_traversal.h"
+
+namespace latinime {
+const bool TypingTraversal::CORRECT_OMISSION = true;
+const bool TypingTraversal::CORRECT_SPACE_SUBSTITUTION = true;
+const bool TypingTraversal::CORRECT_SPACE_OMISSION = true;
+const TypingTraversal TypingTraversal::sInstance;
+}  // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
new file mode 100644
index 0000000000000000000000000000000000000000..16153f8bb37d0e5a90d899ed69fa3f33c169df81
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
@@ -0,0 +1,184 @@
+/*
+ * 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_TYPING_TRAVERSAL_H
+#define LATINIME_TYPING_TRAVERSAL_H
+
+#include <stdint.h>
+
+#include "char_utils.h"
+#include "defines.h"
+#include "dic_node.h"
+#include "dic_node_vector.h"
+#include "dic_traverse_session.h"
+#include "proximity_info_state.h"
+#include "scoring_params.h"
+#include "traversal.h"
+
+namespace latinime {
+class TypingTraversal : public Traversal {
+ public:
+    static const TypingTraversal *getInstance() { return &sInstance; }
+
+    AK_FORCE_INLINE int getMaxPointerCount() const {
+        return MAX_POINTER_COUNT;
+    }
+
+    AK_FORCE_INLINE bool allowsErrorCorrections(const DicNode *const dicNode) const {
+        return dicNode->getNormalizedSpatialDistance()
+                < ScoringParams::MAX_NORM_DISTANCE_FOR_EDIT;
+    }
+
+    AK_FORCE_INLINE bool isOmission(const DicTraverseSession *const traverseSession,
+            const DicNode *const dicNode, const DicNode *const childDicNode) const {
+        if (!CORRECT_OMISSION) {
+            return false;
+        }
+        const int inputSize = traverseSession->getInputSize();
+        // TODO: Don't refer to isCompletion?
+        if (dicNode->isCompletion(inputSize)) {
+            return false;
+        }
+        if (dicNode->canBeIntentionalOmission()) {
+            return true;
+        }
+        const int point0Index = dicNode->getInputIndex(0);
+        const int currentBaseLowerCodePoint =
+                toBaseLowerCase(childDicNode->getNodeCodePoint());
+        const int typedBaseLowerCodePoint =
+                toBaseLowerCase(traverseSession->getProximityInfoState(0)
+                        ->getPrimaryCodePointAt(point0Index));
+        return (currentBaseLowerCodePoint != typedBaseLowerCodePoint);
+    }
+
+    AK_FORCE_INLINE bool isSpaceSubstitutionTerminal(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        if (!CORRECT_SPACE_SUBSTITUTION) {
+            return false;
+        }
+        if (!canDoLookAheadCorrection(traverseSession, dicNode)) {
+            return false;
+        }
+        const int point0Index = dicNode->getInputIndex(0);
+        return dicNode->isTerminalWordNode()
+                && traverseSession->getProximityInfoState(0)->
+                        hasSpaceProximity(point0Index);
+    }
+
+    AK_FORCE_INLINE bool isSpaceOmissionTerminal(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        if (!CORRECT_SPACE_OMISSION) {
+            return false;
+        }
+        const int inputSize = traverseSession->getInputSize();
+        // TODO: Don't refer to isCompletion?
+        if (dicNode->isCompletion(inputSize)) {
+            return false;
+        }
+        if (!dicNode->isTerminalWordNode()) {
+            return false;
+        }
+        const int16_t pointIndex = dicNode->getInputIndex(0);
+        return pointIndex <= inputSize && !dicNode->isTotalInputSizeExceedingLimit()
+                && !dicNode->shouldBeFilterdBySafetyNetForBigram();
+    }
+
+    AK_FORCE_INLINE bool shouldDepthLevelCache(
+            const DicTraverseSession *const traverseSession) const {
+        const int inputSize = traverseSession->getInputSize();
+        return traverseSession->isCacheBorderForTyping(inputSize);
+    }
+
+    AK_FORCE_INLINE bool shouldNodeLevelCache(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        return false;
+    }
+
+    AK_FORCE_INLINE bool canDoLookAheadCorrection(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        const int inputSize = traverseSession->getInputSize();
+        return dicNode->canDoLookAheadCorrection(inputSize);
+    }
+
+    AK_FORCE_INLINE ProximityType getProximityType(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode,
+            const DicNode *const childDicNode) const {
+        return traverseSession->getProximityInfoState(0)->getProximityType(
+                dicNode->getInputIndex(0), childDicNode->getNodeCodePoint(),
+                true /* checkProximityChars */);
+    }
+
+    AK_FORCE_INLINE bool needsToTraverseAllUserInput() const {
+        return true;
+    }
+
+    AK_FORCE_INLINE float getMaxSpatialDistance() const {
+        return ScoringParams::MAX_SPATIAL_DISTANCE;
+    }
+
+    AK_FORCE_INLINE bool allowPartialCommit() const {
+        return true;
+    }
+
+    AK_FORCE_INLINE int getDefaultExpandDicNodeSize() const {
+        return DicNodeVector::DEFAULT_NODES_SIZE_FOR_OPTIMIZATION;
+    }
+
+    AK_FORCE_INLINE bool sameAsTyped(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        return traverseSession->getProximityInfoState(0)->sameAsTyped(
+                dicNode->getOutputWordBuf(), dicNode->getDepth());
+    }
+
+    AK_FORCE_INLINE int getMaxCacheSize() const {
+        return ScoringParams::MAX_CACHE_DIC_NODE_SIZE;
+    }
+
+    AK_FORCE_INLINE bool isPossibleOmissionChildNode(
+            const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode,
+            const DicNode *const dicNode) const {
+        const ProximityType proximityType =
+                getProximityType(traverseSession, parentDicNode, dicNode);
+        if (!DicNodeUtils::isProximityChar(proximityType)) {
+            return false;
+        }
+        return true;
+    }
+
+    AK_FORCE_INLINE bool isGoodToTraverseNextWord(const DicNode *const dicNode) const {
+        const int probability = dicNode->getProbability();
+        if (probability < ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY) {
+            return false;
+        }
+        const int c = dicNode->getOutputWordBuf()[0];
+        const bool shortCappedWord = dicNode->getDepth()
+                < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && isAsciiUpper(c);
+        return !shortCappedWord
+                || probability >= ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED;
+    }
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(TypingTraversal);
+    static const bool CORRECT_OMISSION;
+    static const bool CORRECT_SPACE_SUBSTITUTION;
+    static const bool CORRECT_SPACE_OMISSION;
+    static const TypingTraversal sInstance;
+
+    TypingTraversal() {}
+    ~TypingTraversal() {}
+};
+} // namespace latinime
+#endif // LATINIME_TYPING_TRAVERSAL_H
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6e4b2fb6adf902f063c56dcfe9b6d1fa2b68436b
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
@@ -0,0 +1,23 @@
+/*
+ * 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 "dic_node.h"
+#include "scoring_params.h"
+#include "typing_weighting.h"
+
+namespace latinime {
+const TypingWeighting TypingWeighting::sInstance;
+}  // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8075f41a42f6325f5150f59d7c7d5f95a817aae
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
@@ -0,0 +1,194 @@
+/*
+ * 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_TYPING_WEIGHTING_H
+#define LATINIME_TYPING_WEIGHTING_H
+
+#include "defines.h"
+#include "dic_node_utils.h"
+#include "dic_traverse_session.h"
+#include "weighting.h"
+
+namespace latinime {
+
+class DicNode;
+struct DicNode_InputStateG;
+
+class TypingWeighting : public Weighting {
+ public:
+    static const TypingWeighting *getInstance() { return &sInstance; }
+
+ protected:
+    float getTerminalSpatialCost(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        float cost = 0.0f;
+        if (dicNode->hasMultipleWords()) {
+            cost += ScoringParams::HAS_MULTI_WORD_TERMINAL_COST;
+        }
+        if (dicNode->getProximityCorrectionCount() > 0) {
+            cost += ScoringParams::HAS_PROXIMITY_TERMINAL_COST;
+        }
+        if (dicNode->getEditCorrectionCount() > 0) {
+            cost += ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST;
+        }
+        return cost;
+    }
+
+    float getOmissionCost(const DicNode *const parentDicNode, const DicNode *const dicNode) const {
+        bool sameCodePoint = false;
+        bool isFirstLetterOmission = false;
+        float cost = 0.0f;
+        sameCodePoint = dicNode->isSameNodeCodePoint(parentDicNode);
+        // If the traversal omitted the first letter then the dicNode should now be on the second.
+        isFirstLetterOmission = dicNode->getDepth() == 2;
+        if (isFirstLetterOmission) {
+            cost = ScoringParams::OMISSION_COST_FIRST_CHAR;
+        } else {
+            cost = sameCodePoint ? ScoringParams::OMISSION_COST_SAME_CHAR
+                    : ScoringParams::OMISSION_COST;
+        }
+        return cost;
+    }
+
+    float getMatchedCost(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode,
+            DicNode_InputStateG *inputStateG) const {
+        const int pointIndex = dicNode->getInputIndex(0);
+        // Note: min() required since length can be MAX_POINT_TO_KEY_LENGTH for characters not on
+        // the keyboard (like accented letters)
+        const float length = min(ScoringParams::MAX_SPATIAL_DISTANCE,
+                traverseSession->getProximityInfoState(0)->getPointToKeyLength(
+                        pointIndex, dicNode->getNodeCodePoint()));
+        const float weightedDistance = length * ScoringParams::DISTANCE_WEIGHT_LENGTH;
+        const bool isFirstChar = pointIndex == 0;
+        const bool isProximity = isProximityDicNode(traverseSession, dicNode);
+        const float cost = isProximity ? (isFirstChar ? ScoringParams::FIRST_PROXIMITY_COST
+                : ScoringParams::PROXIMITY_COST) : 0.0f;
+        return weightedDistance + cost;
+    }
+
+    bool isProximityDicNode(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
+        const int pointIndex = dicNode->getInputIndex(0);
+        const int primaryCodePoint = toBaseLowerCase(
+                traverseSession->getProximityInfoState(0)->getPrimaryCodePointAt(pointIndex));
+        const int dicNodeChar = toBaseLowerCase(dicNode->getNodeCodePoint());
+        return primaryCodePoint != dicNodeChar;
+    }
+
+    float getTranspositionCost(
+            const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode,
+            const DicNode *const dicNode) const {
+        const int16_t parentPointIndex = parentDicNode->getInputIndex(0);
+        const int prevCodePoint = parentDicNode->getNodeCodePoint();
+        const float distance1 = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
+                parentPointIndex + 1, prevCodePoint);
+        const int codePoint = dicNode->getNodeCodePoint();
+        const float distance2 = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
+                parentPointIndex, codePoint);
+        const float distance = distance1 + distance2;
+        const float weightedLengthDistance =
+                distance * ScoringParams::DISTANCE_WEIGHT_LENGTH;
+        return ScoringParams::TRANSPOSITION_COST + weightedLengthDistance;
+    }
+
+    float getInsertionCost(
+            const DicTraverseSession *const traverseSession,
+            const DicNode *const parentDicNode, const DicNode *const dicNode) const {
+        const int16_t parentPointIndex = parentDicNode->getInputIndex(0);
+        const int prevCodePoint =
+                traverseSession->getProximityInfoState(0)->getPrimaryCodePointAt(parentPointIndex);
+
+        const int currentCodePoint = dicNode->getNodeCodePoint();
+        const bool sameCodePoint = prevCodePoint == currentCodePoint;
+        const float dist = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
+                parentPointIndex + 1, currentCodePoint);
+        const float weightedDistance = dist * ScoringParams::DISTANCE_WEIGHT_LENGTH;
+        const bool singleChar = dicNode->getDepth() == 1;
+        const float cost = (singleChar ? ScoringParams::INSERTION_COST_FIRST_CHAR : 0.0f)
+                + (sameCodePoint ? ScoringParams::INSERTION_COST_SAME_CHAR
+                        : ScoringParams::INSERTION_COST);
+        return cost + weightedDistance;
+    }
+
+    float getNewWordCost(const DicNode *const dicNode) const {
+        const bool isCapitalized = dicNode->isCapitalized();
+        return isCapitalized ?
+                ScoringParams::COST_NEW_WORD_CAPITALIZED : ScoringParams::COST_NEW_WORD;
+    }
+
+    float getNewWordBigramCost(
+            const DicTraverseSession *const traverseSession, const DicNode *const dicNode,
+            hash_map_compat<int, int16_t> *const bigramCacheMap) const {
+        return DicNodeUtils::getBigramNodeImprobability(traverseSession->getOffsetDict(),
+                dicNode, bigramCacheMap);
+    }
+
+    float getCompletionCost(const DicTraverseSession *const traverseSession,
+            const DicNode *const dicNode) const {
+        // The auto completion starts when the input index is same as the input size
+        const bool firstCompletion = dicNode->getInputIndex(0)
+                == traverseSession->getInputSize();
+        // TODO: Change the cost for the first completion for the gesture?
+        const float cost = firstCompletion ? ScoringParams::COST_FIRST_LOOKAHEAD
+                : ScoringParams::COST_LOOKAHEAD;
+        return cost;
+    }
+
+    float getTerminalLanguageCost(const DicTraverseSession *const traverseSession,
+            const DicNode *const dicNode, const float dicNodeLanguageImprobability) const {
+        const bool hasEditCount = dicNode->getEditCorrectionCount() > 0;
+        const bool isSameLength = dicNode->getDepth() == traverseSession->getInputSize();
+        const bool hasMultipleWords = dicNode->hasMultipleWords();
+        const bool hasProximityErrors = dicNode->getProximityCorrectionCount() > 0;
+        // Gesture input is always assumed to have proximity errors
+        // because the input word shouldn't be treated as perfect
+        const bool isExactMatch = !hasEditCount && !hasMultipleWords
+                && !hasProximityErrors && isSameLength;
+
+        const float totalPrevWordsLanguageCost = dicNode->getTotalPrevWordsLanguageCost();
+        const float languageImprobability = isExactMatch ? 0.0f : dicNodeLanguageImprobability;
+        const float languageWeight = ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
+        // TODO: Caveat: The following equation should be:
+        // totalPrevWordsLanguageCost + (languageImprobability * languageWeight);
+        return (totalPrevWordsLanguageCost + languageImprobability) * languageWeight;
+    }
+
+    AK_FORCE_INLINE bool needsToNormalizeCompoundDistance() const {
+        return false;
+    }
+
+    AK_FORCE_INLINE float getAdditionalProximityCost() const {
+        return ScoringParams::ADDITIONAL_PROXIMITY_COST;
+    }
+
+    AK_FORCE_INLINE float getSubstitutionCost() const {
+        return ScoringParams::SUBSTITUTION_COST;
+    }
+
+    AK_FORCE_INLINE float getSpaceSubstitutionCost() const {
+        return ScoringParams::SPACE_SUBSTITUTION_COST;
+    }
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(TypingWeighting);
+    static const TypingWeighting sInstance;
+
+    TypingWeighting() {}
+    ~TypingWeighting() {}
+};
+} // namespace latinime
+#endif // LATINIME_TYPING_WEIGHTING_H