Fix spellcheck on sentence end

Issue:
Valid words are being erroneously flagged by the spellchecker when
followed by a period.

Resolution:
Valid words followed by periods are no longer flagged. Invalid words
followed by periods are still flagged, and the intent behind the
existing logic to flag and suggest valid words on either side of a
period within a token should not be impacted by this change.

Additional considerations for CHECKABILITY_CONTAINS_PERIOD:
* Empty words are considered invalid. In CHECKABILITY_CONTAINS_PERIOD,
  when a period was the first or last index of text, splitting that
  text on periods caused suggestions to consider potentially valid
  words to be invalid. For example, "this.example." should suggest
  "this example" or "this example.", but no suggestions were being
  given due to the trailing empty string resulting from the split
  operation being considered invalid. This PR modifies this behavior
  such that empty split tokens will not be considered toward word
  validity when generating suggestions for text containing periods.

* Single word sentences (like "Groovy.") were being flagged as invalid
  since the word only exists in the main dictionary as lower case, but
  the validity check within CHECKABILITY_CONTAINS_PERIOD sent text over
  as is. This PR adds, specific to the period checkability logic,
  a fallback validity check for words set to lower case.

Fixes: https://gitlab.com/LineageOS/issues/android/-/issues/4861
Change-Id: Ie445533544fb3ed4b8d2fa6b554e03e0ae5a960f
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 9223923..00bf9a1 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -237,16 +237,23 @@
             // Handle special patterns like email, URI, telephone number.
             final int checkability = getCheckabilityInScript(text, mScript);
             if (CHECKABILITY_CHECKABLE != checkability) {
+                // CHECKABILITY_CONTAINS_PERIOD typo should not be reported when text
+                // is a valid word followed by a single period (end of sentence).
+                boolean periodOnlyAtLastIndex = text.indexOf(
+                        Constants.CODE_PERIOD) == (text.length() - 1);
                 if (CHECKABILITY_CONTAINS_PERIOD == checkability) {
                     final String[] splitText = text.split(Constants.REGEXP_PERIOD);
                     boolean allWordsAreValid = true;
+                    // Validate all words on both sides of periods,
+                    // skip empty tokens due to periods at first/last index
                     for (final String word : splitText) {
-                        if (!mService.isValidWord(mLocale, word)) {
+                        if (!word.isEmpty() && !mService.isValidWord(mLocale, word) &&
+                                !mService.isValidWord(mLocale, word.toLowerCase(mLocale))) {
                             allWordsAreValid = false;
                             break;
                         }
                     }
-                    if (allWordsAreValid) {
+                    if (allWordsAreValid && !periodOnlyAtLastIndex) {
                         return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
                                 | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS,
                                 new String[] {
@@ -256,7 +263,7 @@
                 return mService.isValidWord(mLocale, text) ?
                         AndroidSpellCheckerService.getInDictEmptySuggestions() :
                         AndroidSpellCheckerService.getNotInDictEmptySuggestions(
-                                CHECKABILITY_CONTAINS_PERIOD == checkability /* reportAsTypo */);
+                                !periodOnlyAtLastIndex);
             }
 
             // Handle normal words.