Merge "[Rlog39] Remove unnecessary commitCurrentLogUnit() call"
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 5da0f1b..1cdc3b5 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -76,7 +76,7 @@
     /**
      * Returns a file address from a resource, or null if it cannot be opened.
      */
-    private static AssetFileAddress loadFallbackResource(final Context context,
+    public static AssetFileAddress loadFallbackResource(final Context context,
             final int fallbackResId) {
         final AssetFileDescriptor afd = context.getResources().openRawResourceFd(fallbackResId);
         if (afd == null) {
@@ -149,7 +149,7 @@
      * @param context the context on which to open the files upon.
      * @return an array of binary dictionary files, which may be empty but may not be null.
      */
-    private static File[] getCachedWordLists(final String locale, final Context context) {
+    public static File[] getCachedWordLists(final String locale, final Context context) {
         final File[] directoryList = DictionaryInfoUtils.getCachedDirectoryList(context);
         if (null == directoryList) return EMPTY_FILE_ARRAY;
         final HashMap<String, FileAndMatchLevel> cacheFiles = CollectionUtils.newHashMap();
diff --git a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
index c676bf1..8f16a8e 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin;
 
 import android.content.Context;
+import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.util.Log;
 
@@ -26,6 +27,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Locale;
 
 /**
@@ -41,6 +43,18 @@
     // 6 digits - unicode is limited to 21 bits
     private static final int MAX_HEX_DIGITS_FOR_CODEPOINT = 6;
 
+    public static class DictionaryInfo {
+        public final Locale mLocale;
+        public final AssetFileAddress mFileAddress;
+        public final int mVersion;
+        public DictionaryInfo(final Locale locale, final AssetFileAddress fileAddress,
+                final int version) {
+            mLocale = locale;
+            mFileAddress = fileAddress;
+            mVersion = version;
+        }
+    }
+
     private DictionaryInfoUtils() {
         // Private constructor to forbid instantation of this helper class.
     }
@@ -234,12 +248,79 @@
 
     public static FileHeader getDictionaryFileHeaderOrNull(final File file) {
         try {
-            final FileHeader header = BinaryDictIOUtils.getDictionaryFileHeader(file);
-            return header;
+            return BinaryDictIOUtils.getDictionaryFileHeader(file, 0, file.length());
         } catch (UnsupportedFormatException e) {
             return null;
         } catch (IOException e) {
             return null;
         }
     }
+
+    private static DictionaryInfo createDictionaryInfoFromFileAddress(
+            final AssetFileAddress fileAddress) {
+        final FileHeader header = BinaryDictIOUtils.getDictionaryFileHeaderOrNull(
+                new File(fileAddress.mFilename), fileAddress.mOffset, fileAddress.mLength);
+        final Locale locale = LocaleUtils.constructLocaleFromString(header.getLocaleString());
+        final String version = header.getVersion();
+        return new DictionaryInfo(locale, fileAddress, Integer.parseInt(version));
+    }
+
+    private static void addOrUpdateDictInfo(final ArrayList<DictionaryInfo> dictList,
+            final DictionaryInfo newElement) {
+        for (final DictionaryInfo info : dictList) {
+            if (info.mLocale.equals(newElement.mLocale)) {
+                if (newElement.mVersion <= info.mVersion) {
+                    return;
+                }
+                dictList.remove(info);
+            }
+        }
+        dictList.add(newElement);
+    }
+
+    public static ArrayList<DictionaryInfo> getCurrentDictionaryFileNameAndVersionInfo(
+            final Context context) {
+        final ArrayList<DictionaryInfo> dictList = CollectionUtils.newArrayList();
+
+        // Retrieve downloaded dictionaries
+        final File[] directoryList = getCachedDirectoryList(context);
+        for (final File directory : directoryList) {
+            final String localeString = getWordListIdFromFileName(directory.getName());
+            File[] dicts = BinaryDictionaryGetter.getCachedWordLists(localeString, context);
+            for (final File dict : dicts) {
+                final String wordListId = getWordListIdFromFileName(dict.getName());
+                if (!DictionaryInfoUtils.isMainWordListId(wordListId)) continue;
+                final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
+                final AssetFileAddress fileAddress = AssetFileAddress.makeFromFile(dict);
+                final DictionaryInfo dictionaryInfo =
+                        createDictionaryInfoFromFileAddress(fileAddress);
+                // Protect against cases of a less-specific dictionary being found, like an
+                // en dictionary being used for an en_US locale. In this case, the en dictionary
+                // should be used for en_US but discounted for listing purposes.
+                if (!dictionaryInfo.mLocale.equals(locale)) continue;
+                addOrUpdateDictInfo(dictList, dictionaryInfo);
+            }
+        }
+
+        // Retrieve files from assets
+        final Resources resources = context.getResources();
+        final AssetManager assets = resources.getAssets();
+        for (final String localeString : assets.getLocales()) {
+            final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
+            final int resourceId =
+                    DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
+                            context.getResources(), locale);
+            if (0 == resourceId) continue;
+            final AssetFileAddress fileAddress =
+                    BinaryDictionaryGetter.loadFallbackResource(context, resourceId);
+            final DictionaryInfo dictionaryInfo = createDictionaryInfoFromFileAddress(fileAddress);
+            // Protect against cases of a less-specific dictionary being found, like an
+            // en dictionary being used for an en_US locale. In this case, the en dictionary
+            // should be used for en_US but discounted for listing purposes.
+            if (!dictionaryInfo.mLocale.equals(locale)) continue;
+            addOrUpdateDictInfo(dictList, dictionaryInfo);
+        }
+
+        return dictList;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
index d9e4bb6..9f91639 100644
--- a/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
+++ b/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
@@ -39,7 +39,6 @@
 public class ExternalDictionaryGetterForDebug {
     private static final String SOURCE_FOLDER = Environment.getExternalStorageDirectory().getPath()
             + "/Download";
-    private static final String DICTIONARY_LOCALE_ATTRIBUTE = "locale";
 
     private static String[] findDictionariesInTheDownloadedFolder() {
         final File[] files = new File(SOURCE_FOLDER).listFiles();
@@ -90,8 +89,7 @@
         final File file = new File(SOURCE_FOLDER, fileName.toString());
         final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file);
         final StringBuilder message = new StringBuilder();
-        final String locale =
-                header.mDictionaryOptions.mAttributes.get(DICTIONARY_LOCALE_ATTRIBUTE);
+        final String locale = header.getLocaleString();
         for (String key : header.mDictionaryOptions.mAttributes.keySet()) {
             message.append(key + " = " + header.mDictionaryOptions.mAttributes.get(key));
             message.append("\n");
@@ -123,13 +121,11 @@
         BufferedOutputStream outputStream = null;
         File tempFile = null;
         try {
-            final String locale =
-                    header.mDictionaryOptions.mAttributes.get(DICTIONARY_LOCALE_ATTRIBUTE);
+            final String locale = header.getLocaleString();
             // Create the id for a main dictionary for this locale
             final String id = BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY
                     + BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale;
-            final String finalFileName =
-                    DictionaryInfoUtils.getCacheFileName(id, locale, context);
+            final String finalFileName = DictionaryInfoUtils.getCacheFileName(id, locale, context);
             final String tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
             tempFile = new File(tempFileName);
             tempFile.delete();
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
index 9e1f751..c87a925 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
@@ -988,20 +988,35 @@
      * This is quite resource intensive - don't call when performance is critical.
      *
      * @param file The file to read.
+     * @param offset The offset in the file where to start reading the data.
+     * @param length The length of the data file.
      */
     private static final int HEADER_READING_BUFFER_SIZE = 16384;
-    public static FileHeader getDictionaryFileHeader(final File file)
-        throws FileNotFoundException, IOException, UnsupportedFormatException {
+    public static FileHeader getDictionaryFileHeader(
+            final File file, final long offset, final long length)
+            throws FileNotFoundException, IOException, UnsupportedFormatException {
         final byte[] buffer = new byte[HEADER_READING_BUFFER_SIZE];
         final FileInputStream inStream = new FileInputStream(file);
         try {
             inStream.read(buffer);
             final BinaryDictInputOutput.ByteBufferWrapper wrapper =
                     new BinaryDictInputOutput.ByteBufferWrapper(inStream.getChannel().map(
-                            FileChannel.MapMode.READ_ONLY, 0, file.length()));
+                            FileChannel.MapMode.READ_ONLY, offset, length));
             return BinaryDictInputOutput.readHeader(wrapper);
         } finally {
             inStream.close();
         }
     }
+
+    public static FileHeader getDictionaryFileHeaderOrNull(final File file, final long offset,
+            final long length) {
+        try {
+            final FileHeader header = getDictionaryFileHeader(file, offset, length);
+            return header;
+        } catch (UnsupportedFormatException e) {
+            return null;
+        } catch (IOException e) {
+            return null;
+        }
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index c22ea3b..83acca8 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -256,12 +256,24 @@
         public final int mHeaderSize;
         public final DictionaryOptions mDictionaryOptions;
         public final FormatOptions mFormatOptions;
+        private static final String DICTIONARY_VERSION_ATTRIBUTE = "version";
+        private static final String DICTIONARY_LOCALE_ATTRIBUTE = "locale";
         public FileHeader(final int headerSize, final DictionaryOptions dictionaryOptions,
                 final FormatOptions formatOptions) {
             mHeaderSize = headerSize;
             mDictionaryOptions = dictionaryOptions;
             mFormatOptions = formatOptions;
         }
+
+        // Helper method to get the locale as a String
+        public String getLocaleString() {
+            return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_LOCALE_ATTRIBUTE);
+        }
+
+        // Helper method to get the version String
+        public String getVersion() {
+            return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_VERSION_ATTRIBUTE);
+        }
     }
 
     private FormatSpec() {
diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h
index 0873dae..34f794d 100644
--- a/native/jni/src/correction.h
+++ b/native/jni/src/correction.h
@@ -170,11 +170,10 @@
         if (n <= 0) return 1;
         if (base == 2) {
             return n < 31 ? 1 << n : S_INT_MAX;
-        } else {
-            int ret = base;
-            for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret);
-            return ret;
         }
+        int ret = base;
+        for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret);
+        return ret;
     }
 
     AK_FORCE_INLINE static void multiplyRate(const int rate, int *freq) {
@@ -318,13 +317,11 @@
     addCharToCurrentWord(c);
     mTerminalInputIndex = mInputIndex - (inputIndexIncremented ? 1 : 0);
     mTerminalOutputIndex = mOutputIndex;
+    incrementOutputIndex();
     if (mNeedsToTraverseAllNodes && isTerminal) {
-        incrementOutputIndex();
         return TRAVERSE_ALL_ON_TERMINAL;
-    } else {
-        incrementOutputIndex();
-        return TRAVERSE_ALL_NOT_ON_TERMINAL;
     }
+    return TRAVERSE_ALL_NOT_ON_TERMINAL;
 }
 
 inline Correction::CorrectionType Correction::processUnrelatedCorrectionType() {
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 9883168..a1fdae7 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -267,21 +267,6 @@
 // loading time, and acceptable even for several initial lookups which involve page faults.
 #define USE_MMAP_FOR_DICTIONARY
 
-// 22-bit address = ~4MB dictionary size limit, which on average would be about 200k-300k words
-#define ADDRESS_MASK 0x3FFFFF
-
-// The bit that decides if an address follows in the next 22 bits
-#define FLAG_ADDRESS_MASK 0x40
-// The bit that decides if this is a terminal node for a word. The node could still have children,
-// if the word has other endings.
-#define FLAG_TERMINAL_MASK 0x80
-
-#define FLAG_BIGRAM_READ 0x80
-#define FLAG_BIGRAM_CHILDEXIST 0x40
-#define FLAG_BIGRAM_CONTINUED 0x80
-#define FLAG_BIGRAM_FREQ 0x7F
-
-#define DICTIONARY_VERSION_MIN 200
 #define NOT_VALID_WORD (-99)
 #define NOT_A_CODE_POINT (-1)
 #define NOT_A_DISTANCE (-1)
@@ -297,10 +282,6 @@
 #define KEYCODE_HYPHEN_MINUS '-'
 
 #define CALIBRATE_SCORE_BY_TOUCH_COORDINATES true
-
-#define SUGGEST_WORDS_WITH_MISSING_CHARACTER true
-#define SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER true
-#define SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS true
 #define SUGGEST_MULTIPLE_WORDS true
 
 // The following "rate"s are used as a multiplier before dividing by 100, so they are in percent.
@@ -366,7 +347,6 @@
 #define DEFAULT_MAX_DIGRAPH_SEARCH_DEPTH 5
 
 #define MIN_USER_TYPED_LENGTH_FOR_MULTIPLE_WORD_SUGGESTION 3
-#define MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION 3
 
 // TODO: Remove
 #define MAX_POINTER_COUNT 1
@@ -390,14 +370,11 @@
 #error "BIGRAM_FILTER_MODULO is larger than BIGRAM_FILTER_BYTE_SIZE"
 #endif
 
-template<typename T> inline T min(T a, T b) { return a < b ? a : b; }
-template<typename T> inline T max(T a, T b) { return a > b ? a : b; }
+template<typename T> AK_FORCE_INLINE const T &min(const T &a, const T &b) { return a < b ? a : b; }
+template<typename T> AK_FORCE_INLINE const T &max(const T &a, const T &b) { return a > b ? a : b; }
 
 #define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
 
-// The ratio of neutral area radius to sweet spot radius.
-#define NEUTRAL_AREA_RADIUS_RATIO 1.3f
-
 // DEBUG
 #define INPUTLENGTH_FOR_DEBUG (-1)
 #define MIN_OUTPUT_INDEX_FOR_DEBUG (-1)
diff --git a/native/jni/src/proximity_info_params.cpp b/native/jni/src/proximity_info_params.cpp
index 5a51f62..f7b3d4d 100644
--- a/native/jni/src/proximity_info_params.cpp
+++ b/native/jni/src/proximity_info_params.cpp
@@ -25,6 +25,20 @@
 const int ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR =
         1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
 const float ProximityInfoParams::NOT_A_DISTANCE_FLOAT = -1.0f;
+
+// Per method constants
+const float ProximityInfoParams::NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
+const float ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_DISTANCE = 2.0f;
+const float ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN = 0.01f;
+const int ProximityInfoParams::DISTANCE_BASE_SCALE = 100;
+const float ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_POINT_SCORE = 0.6f;
+const int ProximityInfoParams::CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25;
+const float ProximityInfoParams::NOT_LOCALMIN_DISTANCE_SCORE = -1.0f;
+const float ProximityInfoParams::LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f;
+const float ProximityInfoParams::CORNER_ANGLE_THRESHOLD_FOR_POINT_SCORE = M_PI_F * 2.0f / 3.0f;
+const float ProximityInfoParams::CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f;
+const float ProximityInfoParams::CORNER_SCORE = 1.0f;
+
 // TODO: Investigate if this is required
 const float ProximityInfoParams::SEARCH_KEY_RADIUS_RATIO = 0.95f;
 } // namespace latinime
diff --git a/native/jni/src/proximity_info_params.h b/native/jni/src/proximity_info_params.h
index b941fec..978b999 100644
--- a/native/jni/src/proximity_info_params.h
+++ b/native/jni/src/proximity_info_params.h
@@ -30,6 +30,26 @@
     static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
     static const float NOT_A_DISTANCE_FLOAT;
     static const float SEARCH_KEY_RADIUS_RATIO;
+
+    // Used by ProximityInfoStateUtils::initGeometricDistanceInfos()
+    static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD;
+
+    // Used by ProximityInfoStateUtils::updateNearKeysDistances()
+    static const float NEAR_KEY_THRESHOLD_FOR_DISTANCE;
+
+    // Used by ProximityInfoStateUtils::isPrevLocalMin()
+    static const float MARGIN_FOR_PREV_LOCAL_MIN;
+
+    // Used by ProximityInfoStateUtils::getPointScore()
+    static const int DISTANCE_BASE_SCALE;
+    static const float NEAR_KEY_THRESHOLD_FOR_POINT_SCORE;
+    static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE;
+    static const float NOT_LOCALMIN_DISTANCE_SCORE;
+    static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE;
+    static const float CORNER_ANGLE_THRESHOLD_FOR_POINT_SCORE;
+    static const float CORNER_SUM_ANGLE_THRESHOLD;
+    static const float CORNER_SCORE;
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoParams);
     static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index 141be26..fbdc2c8 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -246,11 +246,6 @@
     return UNRELATED_CHAR;
 }
 
-int ProximityInfoState::getSpaceY() const {
-    const int keyId = mProximityInfo->getKeyIndexOf(KEYCODE_SPACE);
-    return mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
-}
-
 // Puts possible characters into filter and returns new filter size.
 int ProximityInfoState::getAllPossibleChars(
         const size_t index, int *const filter, const int filterSize) const {
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index ff1b350..0386450 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -155,8 +155,6 @@
     ProximityType getMatchedProximityId(const int index, const int c,
             const bool checkProximityChars, int *proximityIndex = 0) const;
 
-    int getSpaceY() const;
-
     int getAllPossibleChars(const size_t startIndex, int *const filter, const int filterSize) const;
 
     float getSpeedRate(const int index) const {
diff --git a/native/jni/src/proximity_info_state_utils.cpp b/native/jni/src/proximity_info_state_utils.cpp
index ac74a4e..da3f03d 100644
--- a/native/jni/src/proximity_info_state_utils.cpp
+++ b/native/jni/src/proximity_info_state_utils.cpp
@@ -138,13 +138,13 @@
     return inputProximities + (index * MAX_PROXIMITY_CHARS_SIZE);
 }
 
-/* static */ int ProximityInfoStateUtils::getPrimaryCodePointAt(
-        const int *const inputProximities, const int index) {
+/* static */ int ProximityInfoStateUtils::getPrimaryCodePointAt(const int *const inputProximities,
+        const int index) {
     return getProximityCodePointsAt(inputProximities, index)[0];
 }
 
-/* static */ void ProximityInfoStateUtils::initPrimaryInputWord(
-        const int inputSize, const int *const inputProximities, int *primaryInputWord) {
+/* static */ void ProximityInfoStateUtils::initPrimaryInputWord(const int inputSize,
+        const int *const inputProximities, int *primaryInputWord) {
     memset(primaryInputWord, 0, sizeof(primaryInputWord[0]) * MAX_WORD_LENGTH);
     for (int i = 0; i < inputSize; ++i) {
         primaryInputWord[i] = getPrimaryCodePointAt(inputProximities, i);
@@ -153,8 +153,7 @@
 
 /* static */ float ProximityInfoStateUtils::calculateSquaredDistanceFromSweetSpotCenter(
         const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
-        const std::vector<int> *const sampledInputYs, const int keyIndex,
-        const int inputIndex) {
+        const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex) {
     const float sweetSpotCenterX = proximityInfo->getSweetSpotCenterXAt(keyIndex);
     const float sweetSpotCenterY = proximityInfo->getSweetSpotCenterYAt(keyIndex);
     const float inputX = static_cast<float>((*sampledInputXs)[inputIndex]);
@@ -164,8 +163,7 @@
 
 /* static */ float ProximityInfoStateUtils::calculateNormalizedSquaredDistance(
         const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
-        const std::vector<int> *const sampledInputYs,
-        const int keyIndex, const int inputIndex) {
+        const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex) {
     if (keyIndex == NOT_AN_INDEX) {
         return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
     }
@@ -182,11 +180,9 @@
 }
 
 /* static */ void ProximityInfoStateUtils::initNormalizedSquaredDistances(
-        const ProximityInfo *const proximityInfo, const int inputSize,
-        const int *inputXCoordinates, const int *inputYCoordinates,
-        const int *const inputProximities,
-        const std::vector<int> *const sampledInputXs,
-        const std::vector<int> *const sampledInputYs,
+        const ProximityInfo *const proximityInfo, const int inputSize, const int *inputXCoordinates,
+        const int *inputYCoordinates, const int *const inputProximities,
+        const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs,
         int *normalizedSquaredDistances) {
     memset(normalizedSquaredDistances, NOT_A_DISTANCE,
             sizeof(normalizedSquaredDistances[0]) * MAX_PROXIMITY_CHARS_SIZE * MAX_WORD_LENGTH);
@@ -201,8 +197,7 @@
             a += 0;
             AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y);
         }
-        for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityCodePoints[j] > 0;
-                ++j) {
+        for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityCodePoints[j] > 0; ++j) {
             const int currentCodePoint = proximityCodePoints[j];
             const float squaredDistance =
                     hasInputCoordinates ? calculateNormalizedSquaredDistance(
@@ -227,9 +222,8 @@
 }
 
 /* static */ void ProximityInfoStateUtils::initGeometricDistanceInfos(
-        const ProximityInfo *const proximityInfo, const int keyCount,
-        const int sampledInputSize, const int lastSavedInputSize,
-        const std::vector<int> *const sampledInputXs,
+        const ProximityInfo *const proximityInfo, const int keyCount, const int sampledInputSize,
+        const int lastSavedInputSize, const std::vector<int> *const sampledInputXs,
         const std::vector<int> *const sampledInputYs,
         std::vector<NearKeycodesSet> *SampledNearKeysVector,
         std::vector<float> *SampledDistanceCache_G) {
@@ -237,7 +231,6 @@
     SampledDistanceCache_G->resize(sampledInputSize * keyCount);
     for (int i = lastSavedInputSize; i < sampledInputSize; ++i) {
         (*SampledNearKeysVector)[i].reset();
-        static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
         for (int k = 0; k < keyCount; ++k) {
             const int index = i * keyCount + k;
             const int x = (*sampledInputXs)[i];
@@ -245,7 +238,8 @@
             const float normalizedSquaredDistance =
                     proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
             (*SampledDistanceCache_G)[index] = normalizedSquaredDistance;
-            if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
+            if (normalizedSquaredDistance
+                    < ProximityInfoParams::NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
                 (*SampledNearKeysVector)[i][k] = true;
             }
         }
@@ -265,8 +259,7 @@
 /* static */ float ProximityInfoStateUtils::refreshSpeedRates(const int inputSize,
         const int *const xCoordinates, const int *const yCoordinates, const int *const times,
         const int lastSavedInputSize, const int sampledInputSize,
-        const std::vector<int> *const sampledInputXs,
-        const std::vector<int> *const sampledInputYs,
+        const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs,
         const std::vector<int> *const sampledInputTimes,
         const std::vector<int> *const sampledLengthCache,
         const std::vector<int> *const sampledInputIndice, std::vector<float> *sampledSpeedRates,
@@ -359,14 +352,12 @@
 /* static */ float ProximityInfoStateUtils::updateNearKeysDistances(
         const ProximityInfo *const proximityInfo, const float maxPointToKeyLength, const int x,
         const int y, NearKeysDistanceMap *const currentNearKeysDistances) {
-    static const float NEAR_KEY_THRESHOLD = 2.0f;
-
     currentNearKeysDistances->clear();
     const int keyCount = proximityInfo->getKeyCount();
     float nearestKeyDistance = maxPointToKeyLength;
     for (int k = 0; k < keyCount; ++k) {
         const float dist = proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
-        if (dist < NEAR_KEY_THRESHOLD) {
+        if (dist < ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_DISTANCE) {
             currentNearKeysDistances->insert(std::pair<int, float>(k, dist));
         }
         if (nearestKeyDistance > dist) {
@@ -381,14 +372,15 @@
         const NearKeysDistanceMap *const currentNearKeysDistances,
         const NearKeysDistanceMap *const prevNearKeysDistances,
         const NearKeysDistanceMap *const prevPrevNearKeysDistances) {
-    static const float MARGIN = 0.01f;
-
     for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin();
             it != prevNearKeysDistances->end(); ++it) {
         NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first);
         NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first);
-        if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN)
-                && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) {
+        const bool isPrevPrevNear = (itPP == prevPrevNearKeysDistances->end()
+                || itPP->second > it->second + ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN);
+        const bool isCurrentNear = (itC == currentNearKeysDistances->end()
+                || itC->second > it->second + ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN);
+        if (isPrevPrevNear && isCurrentNear) {
             return true;
         }
     }
@@ -402,15 +394,6 @@
         const NearKeysDistanceMap *const prevNearKeysDistances,
         const NearKeysDistanceMap *const prevPrevNearKeysDistances,
         std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs) {
-    static const int DISTANCE_BASE_SCALE = 100;
-    static const float NEAR_KEY_THRESHOLD = 0.6f;
-    static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25;
-    static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f;
-    static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f;
-    static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f;
-    static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f;
-    static const float CORNER_SCORE = 1.0f;
-
     const size_t size = sampledInputXs->size();
     // If there is only one point, add this point. Besides, if the previous point's distance map
     // is empty, we re-compute nearby keys distances from the current point.
@@ -422,16 +405,17 @@
 
     const int baseSampleRate = mostCommonKeyWidth;
     const int distPrev = getDistanceInt(sampledInputXs->back(), sampledInputYs->back(),
-            (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]) * DISTANCE_BASE_SCALE;
+            (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2])
+                    * ProximityInfoParams::DISTANCE_BASE_SCALE;
     float score = 0.0f;
 
     // Location
     if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances,
         prevPrevNearKeysDistances)) {
-        score += NOT_LOCALMIN_DISTANCE_SCORE;
-    } else if (nearest < NEAR_KEY_THRESHOLD) {
+        score += ProximityInfoParams::NOT_LOCALMIN_DISTANCE_SCORE;
+    } else if (nearest < ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_POINT_SCORE) {
         // Promote points nearby keys
-        score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE;
+        score += ProximityInfoParams::LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE;
     }
     // Angle
     const float angle1 = getAngle(x, y, sampledInputXs->back(), sampledInputYs->back());
@@ -440,9 +424,10 @@
     const float angleDiff = getAngleDiff(angle1, angle2);
 
     // Save corner
-    if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE
-            && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) {
-        score += CORNER_SCORE;
+    if (distPrev > baseSampleRate * ProximityInfoParams::CORNER_CHECK_DISTANCE_THRESHOLD_SCALE
+            && (sumAngle > ProximityInfoParams::CORNER_SUM_ANGLE_THRESHOLD
+                    || angleDiff > ProximityInfoParams::CORNER_ANGLE_THRESHOLD_FOR_POINT_SCORE)) {
+        score += ProximityInfoParams::CORNER_SCORE;
     }
     return score;
 }
@@ -1033,7 +1018,7 @@
         const ProximityInfo *const proximityInfo, const int sampledInputSize,
         const std::vector<hash_map_compat<int, float> > *const charProbabilities,
         int *const codePointBuf) {
-    ASSERT(charProbabilities->size() >= 0 && sampledInputSize >= 0);
+    ASSERT(sampledInputSize >= 0);
     memset(codePointBuf, 0, sizeof(codePointBuf[0]) * MAX_WORD_LENGTH);
     static const float DEMOTION_LOG_PROBABILITY = 0.3f;
     int index = 0;
diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h
index 8a22f05..54e8007 100644
--- a/native/jni/src/words_priority_queue.h
+++ b/native/jni/src/words_priority_queue.h
@@ -63,10 +63,9 @@
             const int minScore = sw->mScore;
             if (minScore >= score) {
                 return;
-            } else {
-                sw->mUsed = false;
-                mSuggestions.pop();
             }
+            sw->mUsed = false;
+            mSuggestions.pop();
         }
         if (sw == 0) {
             sw = getFreeSuggestedWord(score, word, wordLength, type);