Surface the distance after first word for autocommit.

Bug: 9059617
Change-Id: Ie9b4cc8148ae8e0ff437b3337ab6c1bde95500f5
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 89dfa39..c2aa8ba 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -375,7 +375,7 @@
     CT_TERMINAL,
     CT_TERMINAL_INSERTION,
     // Create new word with space omission
-    CT_NEW_WORD_SPACE_OMITTION,
+    CT_NEW_WORD_SPACE_OMISSION,
     // Create new word with space substitution
     CT_NEW_WORD_SPACE_SUBSTITUTION,
 } CorrectionType;
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 41ef9d2..9099e82 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -38,10 +38,10 @@
         INTS_TO_CHARS(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, \
                 mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(), prevWordCharBuf, \
                 NELEMS(prevWordCharBuf)); \
-        AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %s, %d,,", header, \
+        AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %s, %d, %5f,", header, \
                 getSpatialDistanceForScoring(), getLanguageDistanceForScoring(), \
                 getNormalizedCompoundDistance(), getRawLength(), prevWordCharBuf, charBuf, \
-                getInputIndex(0)); \
+                getInputIndex(0), getNormalizedCompoundDistanceAfterFirstWord()); \
         } while (0)
 #else
 #define LOGI_SHOW_ADD_COST_PROP
@@ -434,6 +434,13 @@
         return mDicNodeState.mDicNodeStateScoring.getLanguageDistance();
     }
 
+    // For space-aware gestures, we store the normalized distance at the char index
+    // that ends the first word of the suggestion. We call this the distance after
+    // first word.
+    float getNormalizedCompoundDistanceAfterFirstWord() const {
+        return mDicNodeState.mDicNodeStateScoring.getNormalizedCompoundDistanceAfterFirstWord();
+    }
+
     float getLanguageDistanceRatePerWordForScoring() const {
         const float langDist = getLanguageDistanceForScoring();
         const float totalWordCount =
@@ -565,6 +572,12 @@
                 inputSize, getTotalInputIndex(), errorType);
     }
 
+    // Saves the current normalized compound distance for space-aware gestures.
+    // See getNormalizedCompoundDistanceAfterFirstWord for details.
+    AK_FORCE_INLINE void saveNormalizedCompoundDistanceAfterFirstWordIfNoneYet() {
+        mDicNodeState.mDicNodeStateScoring.saveNormalizedCompoundDistanceAfterFirstWordIfNoneYet();
+    }
+
     // Caveat: Must not be called outside Weighting
     // This restriction is guaranteed by "friend"
     AK_FORCE_INLINE void forwardInputIndex(const int pointerId, const int count,
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
index 4c88422..3c85d0e 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h
@@ -31,7 +31,8 @@
               mDigraphIndex(DigraphUtils::NOT_A_DIGRAPH_INDEX),
               mEditCorrectionCount(0), mProximityCorrectionCount(0),
               mNormalizedCompoundDistance(0.0f), mSpatialDistance(0.0f), mLanguageDistance(0.0f),
-              mRawLength(0.0f), mExactMatch(true) {
+              mRawLength(0.0f), mExactMatch(true),
+              mNormalizedCompoundDistanceAfterFirstWord(MAX_VALUE_FOR_WEIGHTING) {
     }
 
     virtual ~DicNodeStateScoring() {}
@@ -45,6 +46,7 @@
         mRawLength = 0.0f;
         mDoubleLetterLevel = NOT_A_DOUBLE_LETTER;
         mDigraphIndex = DigraphUtils::NOT_A_DIGRAPH_INDEX;
+        mNormalizedCompoundDistanceAfterFirstWord = MAX_VALUE_FOR_WEIGHTING;
         mExactMatch = true;
     }
 
@@ -58,6 +60,8 @@
         mDoubleLetterLevel = scoring->mDoubleLetterLevel;
         mDigraphIndex = scoring->mDigraphIndex;
         mExactMatch = scoring->mExactMatch;
+        mNormalizedCompoundDistanceAfterFirstWord =
+                scoring->mNormalizedCompoundDistanceAfterFirstWord;
     }
 
     void addCost(const float spatialCost, const float languageCost, const bool doNormalization,
@@ -86,6 +90,17 @@
         }
     }
 
+    // Saves the current normalized distance for space-aware gestures.
+    // See getNormalizedCompoundDistanceAfterFirstWord for details.
+    void saveNormalizedCompoundDistanceAfterFirstWordIfNoneYet() {
+        // We get called here after each word. We only want to store the distance after
+        // the first word, so if we already have a distance we skip saving -- hence "IfNoneYet"
+        // in the method name.
+        if (mNormalizedCompoundDistanceAfterFirstWord >= MAX_VALUE_FOR_WEIGHTING) {
+            mNormalizedCompoundDistanceAfterFirstWord = getNormalizedCompoundDistance();
+        }
+    }
+
     void addRawLength(const float rawLength) {
         mRawLength += rawLength;
     }
@@ -102,6 +117,13 @@
         return mNormalizedCompoundDistance;
     }
 
+    // For space-aware gestures, we store the normalized distance at the char index
+    // that ends the first word of the suggestion. We call this the distance after
+    // first word.
+    float getNormalizedCompoundDistanceAfterFirstWord() const {
+        return mNormalizedCompoundDistanceAfterFirstWord;
+    }
+
     float getSpatialDistance() const {
         return mSpatialDistance;
     }
@@ -178,6 +200,7 @@
     float mLanguageDistance;
     float mRawLength;
     bool mExactMatch;
+    float mNormalizedCompoundDistanceAfterFirstWord;
 
     AK_FORCE_INLINE void addDistance(float spatialDistance, float languageDistance,
             bool doNormalization, int inputSize, int totalInputIndex) {
diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp
index f9b777d..0c40168 100644
--- a/native/jni/src/suggest/core/policy/weighting.cpp
+++ b/native/jni/src/suggest/core/policy/weighting.cpp
@@ -38,7 +38,7 @@
     case CT_SUBSTITUTION:
         PROF_SUBSTITUTION(node->mProfiler);
         return;
-    case CT_NEW_WORD_SPACE_OMITTION:
+    case CT_NEW_WORD_SPACE_OMISSION:
         PROF_NEW_WORD(node->mProfiler);
         return;
     case CT_MATCH:
@@ -93,6 +93,11 @@
     }
     dicNode->addCost(spatialCost, languageCost, weighting->needsToNormalizeCompoundDistance(),
             inputSize, errorType);
+    if (CT_NEW_WORD_SPACE_OMISSION == correctionType) {
+        // When we are on a terminal, we save the current distance for evaluating
+        // when to auto-commit partial suggestions.
+        dicNode->saveNormalizedCompoundDistanceAfterFirstWordIfNoneYet();
+    }
 }
 
 /* static */ float Weighting::getSpatialCost(const Weighting *const weighting,
@@ -108,7 +113,7 @@
     case CT_SUBSTITUTION:
         // only used for typing
         return weighting->getSubstitutionCost();
-    case CT_NEW_WORD_SPACE_OMITTION:
+    case CT_NEW_WORD_SPACE_OMISSION:
         return weighting->getNewWordSpatialCost(traverseSession, dicNode, inputStateG);
     case CT_MATCH:
         return weighting->getMatchedCost(traverseSession, dicNode, inputStateG);
@@ -138,7 +143,7 @@
         return 0.0f;
     case CT_SUBSTITUTION:
         return 0.0f;
-    case CT_NEW_WORD_SPACE_OMITTION:
+    case CT_NEW_WORD_SPACE_OMISSION:
         return weighting->getNewWordBigramLanguageCost(
                 traverseSession, parentDicNode, multiBigramMap);
     case CT_MATCH:
@@ -173,7 +178,7 @@
             return 0; /* 0 because CT_MATCH will be called */
         case CT_SUBSTITUTION:
             return 0; /* 0 because CT_MATCH will be called */
-        case CT_NEW_WORD_SPACE_OMITTION:
+        case CT_NEW_WORD_SPACE_OMISSION:
             return 0;
         case CT_MATCH:
             return 1;
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index b1340e1..e20bc49 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -574,7 +574,7 @@
     DicNodeUtils::initAsRootWithPreviousWord(
             traverseSession->getDictionaryStructurePolicy(), dicNode, &newDicNode);
     const CorrectionType correctionType = spaceSubstitution ?
-            CT_NEW_WORD_SPACE_SUBSTITUTION : CT_NEW_WORD_SPACE_OMITTION;
+            CT_NEW_WORD_SPACE_SUBSTITUTION : CT_NEW_WORD_SPACE_OMISSION;
     Weighting::addCostAndForwardInputIndex(WEIGHTING, correctionType, traverseSession, dicNode,
             &newDicNode, traverseSession->getMultiBigramMap());
     if (newDicNode.getCompoundDistance() < static_cast<float>(MAX_VALUE_FOR_WEIGHTING)) {
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
index 408b12a..5b6b5e8 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
@@ -47,7 +47,7 @@
         case CT_TERMINAL_INSERTION:
         case CT_TRANSPOSITION:
             return ET_EDIT_CORRECTION;
-        case CT_NEW_WORD_SPACE_OMITTION:
+        case CT_NEW_WORD_SPACE_OMISSION:
         case CT_NEW_WORD_SPACE_SUBSTITUTION:
             return ET_NEW_WORD;
         case CT_TERMINAL: