Calibrate the scores of the proximity chars according to the distances.

+1      75
-1      27
+2       0
-2       0
+3       0
-3       0
+4      30
-4      48
+5      37
-5      27
+6       4
-6      35
+7       9
-7      18

Change-Id: I3c6ab06a0084c18ab595147c36c2ff4b1e961a7b
diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp
index de3f421..20fa18a 100644
--- a/native/src/proximity_info.cpp
+++ b/native/src/proximity_info.cpp
@@ -44,13 +44,21 @@
           CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
           CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
           KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
-          mInputXCoordinates(NULL), mInputYCoordinates(NULL) {
+          HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
+                  && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
+                  && sweetSpotCenterYs && sweetSpotRadii),
+          mInputXCoordinates(NULL), mInputYCoordinates(NULL),
+          mTouchPositionCorrectionEnabled(false) {
     const int len = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
     mProximityCharsArray = new uint32_t[len];
+    mNormalizedSquaredDistances = new int[len];
     if (DEBUG_PROXIMITY_INFO) {
         LOGI("Create proximity info array %d", len);
     }
     memcpy(mProximityCharsArray, proximityCharsArray, len * sizeof(mProximityCharsArray[0]));
+    for (int i = 0; i < len; ++i) {
+        mNormalizedSquaredDistances[i] = NOT_A_DISTANCE;
+    }
 
     copyOrFillZero(mKeyXCoordinates, keyXCoordinates, KEY_COUNT * sizeof(mKeyXCoordinates[0]));
     copyOrFillZero(mKeyYCoordinates, keyYCoordinates, KEY_COUNT * sizeof(mKeyYCoordinates[0]));
@@ -79,6 +87,7 @@
 }
 
 ProximityInfo::~ProximityInfo() {
+    delete[] mNormalizedSquaredDistances;
     delete[] mProximityCharsArray;
 }
 
@@ -109,52 +118,61 @@
     mInputCodes = inputCodes;
     mInputXCoordinates = xCoordinates;
     mInputYCoordinates = yCoordinates;
+    mTouchPositionCorrectionEnabled =
+            HAS_TOUCH_POSITION_CORRECTION_DATA && xCoordinates && yCoordinates;
     mInputLength = inputLength;
     for (int i = 0; i < inputLength; ++i) {
         mPrimaryInputWord[i] = getPrimaryCharAt(i);
     }
     mPrimaryInputWord[inputLength] = 0;
     for (int i = 0; i < mInputLength; ++i) {
-        float normalizedSquaredDistance = calculateNormalizedSquaredDistance(i);
-        if (normalizedSquaredDistance >= 0.0f) {
-            mNormalizedSquaredDistance[i] =
-                (int)(normalizedSquaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
-        } else {
-            mNormalizedSquaredDistance[i] = NOT_A_DISTANCE;
+        const int *proximityChars = getProximityCharsAt(i);
+        for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityChars[j] > 0; ++j) {
+            const int currentChar = proximityChars[j];
+            const int keyIndex = getKeyIndex(currentChar);
+            const float squaredDistance = calculateNormalizedSquaredDistance(keyIndex, i);
+            if (squaredDistance >= 0.0f) {
+                mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
+                        (int)(squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
+            } else {
+                mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] = (j == 0)
+                        ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO
+                        : PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO;
+            }
         }
     }
 }
 
 inline float square(const float x) { return x * x; }
 
-float ProximityInfo::calculateNormalizedSquaredDistance(int index) const {
+float ProximityInfo::calculateNormalizedSquaredDistance(
+        const int keyIndex, const int inputIndex) const {
     static const float NOT_A_DISTANCE_FLOAT = -1.0f;
-    if (KEY_COUNT == 0 || !mInputXCoordinates || !mInputYCoordinates) {
-        // We do not have the coordinate data
+    if (keyIndex == NOT_A_INDEX) {
         return NOT_A_DISTANCE_FLOAT;
     }
-    const int currentChar = getPrimaryCharAt(index);
-    const unsigned short baseLowerC = Dictionary::toBaseLowerCase(currentChar);
-    if (baseLowerC > MAX_CHAR_CODE) {
+    if (!hasSweetSpotData(keyIndex)) {
         return NOT_A_DISTANCE_FLOAT;
     }
-    const int keyIndex = mCodeToKeyIndex[baseLowerC];
-    if (keyIndex < 0) {
-        return NOT_A_DISTANCE_FLOAT;
-    }
-    const float radius = mSweetSpotRadii[keyIndex];
-    if (radius <= 0.0) {
-        // When there are no calibration data for a key,
-        // the radius of the key is assigned to zero.
-        return NOT_A_DISTANCE;
-    }
-    const float squaredRadius = square(radius);
-    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(keyIndex, index);
+    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(keyIndex, inputIndex);
+    const float squaredRadius = square(mSweetSpotRadii[keyIndex]);
     return squaredDistance / squaredRadius;
 }
 
+int ProximityInfo::getKeyIndex(const int c) const {
+    if (KEY_COUNT == 0 || !mInputXCoordinates || !mInputYCoordinates) {
+        // We do not have the coordinate data
+        return NOT_A_INDEX;
+    }
+    const unsigned short baseLowerC = Dictionary::toBaseLowerCase(c);
+    if (baseLowerC > MAX_CHAR_CODE) {
+        return NOT_A_INDEX;
+    }
+    return mCodeToKeyIndex[baseLowerC];
+}
+
 float ProximityInfo::calculateSquaredDistanceFromSweetSpotCenter(
-        int keyIndex, int inputIndex) const {
+        const int keyIndex, const int inputIndex) const {
     const float sweetSpotCenterX = mSweetSpotCenterXs[keyIndex];
     const float sweetSpotCenterY = mSweetSpotCenterYs[keyIndex];
     const float inputX = (float)mInputXCoordinates[inputIndex];
@@ -202,11 +220,13 @@
 // then the word contains at that position a character close to what the user
 // typed.
 // What the user typed is actually the first character of the array.
+// proximityIndex is a pointer to the variable where getMatchedProximityId returns
+// the index of c in the proximity chars of the input index.
 // Notice : accented characters do not have a proximity list, so they are alone
 // in their list. The non-accented version of the character should be considered
 // "close", but not the other keys close to the non-accented version.
-ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(
-        const int index, const unsigned short c, const bool checkProximityChars) const {
+ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int index,
+        const unsigned short c, const bool checkProximityChars, int *proximityIndex) const {
     const int *currentChars = getProximityCharsAt(index);
     const int firstChar = currentChars[0];
     const unsigned short baseLowerC = Dictionary::toBaseLowerCase(c);
@@ -227,9 +247,14 @@
 
     // Not an exact nor an accent-alike match: search the list of close keys
     int j = 1;
-    while (currentChars[j] > 0 && j < MAX_PROXIMITY_CHARS_SIZE) {
+    while (j < MAX_PROXIMITY_CHARS_SIZE && currentChars[j] > 0) {
         const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
-        if (matched) return NEAR_PROXIMITY_CHAR;
+        if (matched) {
+            if (proximityIndex) {
+                *proximityIndex = j;
+            }
+            return NEAR_PROXIMITY_CHAR;
+        }
         ++j;
     }