From 22931cd94155b5623b9fa52c0596a44aa89bf606 Mon Sep 17 00:00:00 2001
From: Keisuke Kuroyanagi <ksk@google.com>
Date: Thu, 12 Jun 2014 12:26:18 +0900
Subject: [PATCH] Enable Beginning-of-Sentence prediction for contextual dict.

Bug: 14161647
Bug: 14119293
Change-Id: I0c00f13966db88e4de85e245e7bced43c9d474b2
---
 .../latin/ExpandableBinaryDictionary.java     | 10 ++++++++++
 .../personalization/ContextualDictionary.java |  6 ++++++
 ...oid_inputmethod_latin_BinaryDictionary.cpp |  2 +-
 .../suggest/core/session/prev_words_info.h    |  8 ++++++++
 .../v4/ver4_patricia_trie_policy.cpp          | 19 ++++++++++++++++++-
 5 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 4dbfa0bac9..b1966bffc1 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -122,6 +122,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
         return mBinaryDictionary.isValidDictionary();
     }
 
+    // TODO: Remove and always enable beginning of sentence prediction. Currently, this is enabled
+    // only for ContextualDictionary.
+    protected boolean enableBeginningOfSentencePrediction() {
+        return false;
+    }
+
     /**
      * Creates a new expandable binary dictionary.
      *
@@ -398,6 +404,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
                 if (mBinaryDictionary == null) {
                     return null;
                 }
+                if (composer.size() == 0 && prevWordsInfo.mIsBeginningOfSentence
+                        && !enableBeginningOfSentencePrediction()) {
+                    return null;
+                }
                 final ArrayList<SuggestedWordInfo> suggestions =
                         mBinaryDictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
                                 blockOffensiveWords, additionalFeaturesOptions, sessionId,
diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
index 96755a98f0..81ac6cc5fe 100644
--- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
@@ -35,12 +35,18 @@ public class ContextualDictionary extends ExpandableBinaryDictionary {
         // Always reset the contents.
         clear();
     }
+
     @UsedForTesting
     public static ContextualDictionary getDictionary(final Context context, final Locale locale,
             final File dictFile, final String dictNamePrefix) {
         return new ContextualDictionary(context, locale, dictFile);
     }
 
+    @Override
+    protected boolean enableBeginningOfSentencePrediction() {
+        return true;
+    }
+
     @Override
     public boolean isValidWord(final String word) {
         // Strings out of this dictionary should not be considered existing words.
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 476338e378..f62b24cbf5 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -249,7 +249,7 @@ static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz,
     env->GetFloatArrayRegion(inOutLanguageWeight, 0, 1 /* len */, &languageWeight);
     SuggestionResults suggestionResults(MAX_RESULTS);
     const PrevWordsInfo prevWordsInfo(prevWordCodePoints, prevWordCodePointsLength,
-            false /* isStartOfSentence */);
+            isBeginningOfSentence);
     if (givenSuggestOptions.isGesture() || inputSize > 0) {
         // TODO: Use SuggestionResults to return suggestions.
         dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
diff --git a/native/jni/src/suggest/core/session/prev_words_info.h b/native/jni/src/suggest/core/session/prev_words_info.h
index 56c53c1c2a..640f6a2fc8 100644
--- a/native/jni/src/suggest/core/session/prev_words_info.h
+++ b/native/jni/src/suggest/core/session/prev_words_info.h
@@ -85,6 +85,14 @@ class PrevWordsInfo {
         return mPrevWordCodePointCount[n - 1];
     }
 
+    // n is 1-indexed.
+    bool isNthPrevWordBeginningOfSentence(const int n) const {
+        if (n <= 0 || n > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
+            return false;
+        }
+        return mIsBeginningOfSentence[n - 1];
+    }
+
  private:
     DISALLOW_COPY_AND_ASSIGN(PrevWordsInfo);
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 09c7b7d85f..1e10f24c5a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -246,7 +246,24 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
             false /* tryLowerCaseSearch */);
     // TODO: Support N-gram.
     if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
-        return false;
+        if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) {
+            const std::vector<UnigramProperty::ShortcutProperty> shortcuts;
+            const UnigramProperty beginningOfSentenceUnigramProperty(
+                    true /* representsBeginningOfSentence */, true /* isNotAWord */,
+                    false /* isBlacklisted */, MAX_PROBABILITY /* probability */,
+                    NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */, &shortcuts);
+            if (!addUnigramEntry(prevWordsInfo->getNthPrevWordCodePoints(1 /* n */),
+                    prevWordsInfo->getNthPrevWordCodePointCount(1 /* n */),
+                    &beginningOfSentenceUnigramProperty)) {
+                AKLOGE("Cannot add unigram entry for the beginning-of-sentence.");
+                return false;
+            }
+            // Refresh Terminal PtNode positions.
+            prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
+                    false /* tryLowerCaseSearch */);
+        } else {
+            return false;
+        }
     }
     const int word1Pos = getTerminalPtNodePositionOfWord(
             bigramProperty->getTargetCodePoints()->data(),
-- 
GitLab