diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 49b98863f173fe0059cd82b851e4c12aaa274d8d..2f146f86c575fe1cb0cc8e48a1aa1585f23859cb 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -438,15 +438,23 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
         if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE;
         final int len = text.length();
         int capsCount = 1;
+        int letterCount = 1;
         for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) {
-            if (1 != capsCount && i != capsCount) break;
-            if (Character.isUpperCase(text.codePointAt(i))) ++capsCount;
+            if (1 != capsCount && letterCount != capsCount) break;
+            final int codePoint = text.codePointAt(i);
+            if (Character.isUpperCase(codePoint)) {
+                ++capsCount;
+                ++letterCount;
+            } else if (Character.isLetter(codePoint)) {
+                // We need to discount non-letters since they may not be upper-case, but may
+                // still be part of a word (e.g. single quote or dash, as in "IT'S" or "FULL-TIME")
+                ++letterCount;
+            }
         }
-        // We know the first char is upper case. So we want to test if either everything
-        // else is lower case, or if everything else is upper case. If the string is
-        // exactly one char long, then we will arrive here with capsCount 1, and this is
-        // correct, too.
+        // We know the first char is upper case. So we want to test if either every letter other
+        // than the first is lower case, or if they are all upper case. If the string is exactly
+        // one char long, then we will arrive here with letterCount 1, and this is correct, too.
         if (1 == capsCount) return CAPITALIZE_FIRST;
-        return (len == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
+        return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index a8f323999f808115e4ebe1bea608ce9963903535..470943be15b3b5ebaa370e0ca572bce07c4f4bd6 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -28,9 +28,11 @@ import android.view.textservice.TextInfo;
 
 import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
 import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.WordComposer;
 import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
 
 import java.util.ArrayList;
@@ -188,6 +190,35 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
         return (letterCount * 4 < length * 3);
     }
 
+    /**
+     * Helper method to test valid capitalizations of a word.
+     *
+     * If the "text" is lower-case, we test only the exact string.
+     * If the "Text" is capitalized, we test the exact string "Text" and the lower-cased
+     *  version of it "text".
+     * If the "TEXT" is fully upper case, we test the exact string "TEXT", the lower-cased
+     *  version of it "text" and the capitalized version of it "Text".
+     */
+    private boolean isInDictForAnyCapitalization(final Dictionary dict, final String text,
+            final int capitalizeType) {
+        // If the word is in there as is, then it's in the dictionary. If not, we'll test lower
+        // case versions, but only if the word is not already all-lower case or mixed case.
+        if (dict.isValidWord(text)) return true;
+        if (AndroidSpellCheckerService.CAPITALIZE_NONE == capitalizeType) return false;
+
+        // If we come here, we have a capitalized word (either First- or All-).
+        // Downcase the word and look it up again. If the word is only capitalized, we
+        // tested all possibilities, so if it's still negative we can return false.
+        final String lowerCaseText = text.toLowerCase(mLocale);
+        if (dict.isValidWord(lowerCaseText)) return true;
+        if (AndroidSpellCheckerService.CAPITALIZE_FIRST == capitalizeType) return false;
+
+        // If the lower case version is not in the dictionary, it's still possible
+        // that we have an all-caps version of a word that needs to be capitalized
+        // according to the dictionary. E.g. "GERMANS" only exists in the dictionary as "Germans".
+        return dict.isValidWord(StringUtils.toTitleCase(lowerCaseText, mLocale));
+    }
+
     // Note : this must be reentrant
     /**
      * Gets a list of suggestions for a specific string. This returns a list of possible
@@ -272,13 +303,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
                     suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
                             suggestionStr.length(), suggestion.mScore);
                 }
-                isInDict = dictInfo.mDictionary.isValidWord(text);
-                if (!isInDict && AndroidSpellCheckerService.CAPITALIZE_NONE != capitalizeType) {
-                    // We want to test the word again if it's all caps or first caps only.
-                    // If it's fully down, we already tested it, if it's mixed case, we don't
-                    // want to test a lowercase version of it.
-                    isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale));
-                }
+                isInDict = isInDictForAnyCapitalization(dictInfo.mDictionary, text, capitalizeType);
             } finally {
                 if (null != dictInfo) {
                     if (!mDictionaryPool.offer(dictInfo)) {