Fix string iterations in a couple places.

Seems I didn't get how to iterate on a String correctly >.>
Talk about a big bug. Anyway, I think it's working now.

Bug: 5955228
Change-Id: I988c900cf2a16c44b9505cfd4f77c7cda7e592f0
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index b333e48..79441c5 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -75,7 +75,8 @@
         // This assumes '%' is fully available as a non-separator, normal
         // character in a file name. This is probably true for all file systems.
         final StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < name.length(); ++i) {
+        final int nameLength = name.length();
+        for (int i = 0; i < nameLength; i = name.offsetByCodePoints(i, 1)) {
             final int codePoint = name.codePointAt(i);
             if (isFileNameCharacter(codePoint)) {
                 sb.appendCodePoint(codePoint);
@@ -92,7 +93,8 @@
      */
     private static String getWordListIdFromFileName(final String fname) {
         final StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < fname.length(); ++i) {
+        final int fnameLength = fname.length();
+        for (int i = 0; i < fnameLength; i = fname.offsetByCodePoints(i, 1)) {
             final int codePoint = fname.codePointAt(i);
             if ('%' != codePoint) {
                 sb.appendCodePoint(codePoint);
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 8e2f605..589cb6f 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -93,7 +93,8 @@
         mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
         mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
         if (LatinImeLogger.sDBG) {
-            for (int i = 0; i < mMagicSpaceStrippers.length(); ++i) {
+            final int length = mMagicSpaceStrippers.length();
+            for (int i = 0; i < length; i = mMagicSpaceStrippers.offsetByCodePoints(i, 1)) {
                 if (isMagicSpaceSwapper(mMagicSpaceStrippers.codePointAt(i))) {
                     throw new RuntimeException("Char code " + mMagicSpaceStrippers.codePointAt(i)
                             + " is both a magic space swapper and stripper.");
@@ -234,10 +235,12 @@
     }
 
     public boolean isMagicSpaceStripper(int code) {
+        // TODO: this does not work if the code does not fit in a char
         return mMagicSpaceStrippers.contains(String.valueOf((char)code));
     }
 
     public boolean isMagicSpaceSwapper(int code) {
+        // TODO: this does not work if the code does not fit in a char
         return mMagicSpaceSwappers.contains(String.valueOf((char)code));
     }
 
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index bd244b9..fa1b5ef 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -221,7 +221,8 @@
         if (mTrailingSingleQuotesCount > 0) {
             --mTrailingSingleQuotesCount;
         } else {
-            for (int i = mTypedWord.length() - 1; i >= 0; --i) {
+            for (int i = mTypedWord.offsetByCodePoints(mTypedWord.length(), -1);
+                    i >= 0; i = mTypedWord.offsetByCodePoints(i, -1)) {
                 if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break;
                 ++mTrailingSingleQuotesCount;
             }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 88ac043..8ac82ee 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -431,9 +431,9 @@
         // If the first char is not uppercase, then the word is either all lower case,
         // and in either case we return CAPITALIZE_NONE.
         if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE;
-        final int len = text.codePointCount(0, text.length());
+        final int len = text.length();
         int capsCount = 1;
-        for (int i = 1; i < len; ++i) {
+        for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) {
             if (1 != capsCount && i != capsCount) break;
             if (Character.isUpperCase(text.codePointAt(i))) ++capsCount;
         }
@@ -522,13 +522,12 @@
             // Filter contents
             final int length = text.length();
             int letterCount = 0;
-            for (int i = 0; i < length; ++i) {
+            for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
                 final int codePoint = text.codePointAt(i);
                 // Any word containing a '@' is probably an e-mail address
                 // Any word containing a '/' is probably either an ad-hoc combination of two
                 // words or a URI - in either case we don't want to spell check that
-                if ('@' == codePoint
-                        || '/' == codePoint) return true;
+                if ('@' == codePoint || '/' == codePoint) return true;
                 if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount;
             }
             // Guestimate heuristic: perform spell checking if at least 3/4 of the characters
@@ -570,7 +569,7 @@
                         suggestionsLimit);
                 final WordComposer composer = new WordComposer();
                 final int length = text.length();
-                for (int i = 0; i < length; ++i) {
+                for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
                     final int character = text.codePointAt(i);
                     final int proximityIndex =
                             SpellCheckerProximityInfo.getIndexOfCodeForScript(character, mScript);
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 8c0ccd4..af647b8 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -133,7 +133,7 @@
     }
 
     private void type(final String stringToType) {
-        for (int i = 0; i < stringToType.length(); ++i) {
+        for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) {
             type(stringToType.codePointAt(i));
         }
     }
diff --git a/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java b/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java
index 918b1ca..08143d3 100644
--- a/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java
+++ b/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java
@@ -164,7 +164,7 @@
     static private int[] getCodePoints(String word) {
         final int wordLength = word.length();
         int[] array = new int[word.codePointCount(0, wordLength)];
-        for (int i = 0; i < wordLength; ++i) {
+        for (int i = 0; i < wordLength; i = word.offsetByCodePoints(i, 1)) {
             array[i] = word.codePointAt(i);
         }
         return array;