diff options
53 files changed, 549 insertions, 234 deletions
diff --git a/common/src/com/android/inputmethod/latin/common/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java index d3746423e..8f4a1e50d 100644 --- a/common/src/com/android/inputmethod/latin/common/Constants.java +++ b/common/src/com/android/inputmethod/latin/common/Constants.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin.common; +import com.android.inputmethod.annotations.UsedForTesting; + public final class Constants { public static final class Color { /** @@ -305,11 +307,13 @@ public final class Constants { public static final int SCREEN_METRICS_LARGE_TABLET = 2; public static final int SCREEN_METRICS_SMALL_TABLET = 3; + @UsedForTesting public static boolean isPhone(final int screenMetrics) { return screenMetrics == SCREEN_METRICS_SMALL_PHONE || screenMetrics == SCREEN_METRICS_LARGE_PHONE; } + @UsedForTesting public static boolean isTablet(final int screenMetrics) { return screenMetrics == SCREEN_METRICS_SMALL_TABLET || screenMetrics == SCREEN_METRICS_LARGE_TABLET; diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/common/src/com/android/inputmethod/latin/common/StringUtils.java index f96ed0468..bbe46644d 100644 --- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java +++ b/common/src/com/android/inputmethod/latin/common/StringUtils.java @@ -14,19 +14,13 @@ * limitations under the License. */ -package com.android.inputmethod.latin.utils; - -import android.text.Spanned; -import android.text.TextUtils; +package com.android.inputmethod.latin.common; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.common.Constants; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public final class StringUtils { public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case @@ -47,8 +41,67 @@ public final class StringUtils { // This utility class is not publicly instantiable. } + // Taken from android.text.TextUtils. We are extensively using this method in many places, + // some of which don't have the android libraries available. + /** + * Returns true if the string is null or 0-length. + * @param str the string to be examined + * @return true if str is null or zero length + */ + public static boolean isEmpty(CharSequence str) { + if (str == null || str.length() == 0) + return true; + else + return false; + } + + // Taken from android.text.TextUtils to cut the dependency to the Android framework. + /** + * Returns a string containing the tokens joined by delimiters. + * @param tokens an array objects to be joined. Strings will be formed from + * the objects by calling object.toString(). + */ + public static String join(CharSequence delimiter, Iterable tokens) { + StringBuilder sb = new StringBuilder(); + boolean firstTime = true; + for (Object token: tokens) { + if (firstTime) { + firstTime = false; + } else { + sb.append(delimiter); + } + sb.append(token); + } + return sb.toString(); + } + + // Taken from android.text.TextUtils to cut the dependency to the Android framework. + /** + * Returns true if a and b are equal, including if they are both null. + * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if + * both the arguments were instances of String.</i></p> + * @param a first CharSequence to check + * @param b second CharSequence to check + * @return true if a and b are equal + */ + public static boolean equals(CharSequence a, CharSequence b) { + if (a == b) return true; + int length; + if (a != null && b != null && (length = a.length()) == b.length()) { + if (a instanceof String && b instanceof String) { + return a.equals(b); + } else { + for (int i = 0; i < length; i++) { + if (a.charAt(i) != b.charAt(i)) return false; + } + return true; + } + } + return false; + } + public static int codePointCount(final CharSequence text) { - if (TextUtils.isEmpty(text)) return 0; + if (isEmpty(text)) return 0; return Character.codePointCount(text, 0, text.length()); } @@ -78,7 +131,7 @@ public final class StringUtils { public static boolean containsInCommaSplittableText(final String text, final String extraValues) { - if (TextUtils.isEmpty(extraValues)) { + if (isEmpty(extraValues)) { return false; } return containsInArray(text, extraValues.split(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT)); @@ -86,7 +139,7 @@ public final class StringUtils { public static String removeFromCommaSplittableTextIfExists(final String text, final String extraValues) { - if (TextUtils.isEmpty(extraValues)) { + if (isEmpty(extraValues)) { return EMPTY_STRING; } final String[] elements = extraValues.split(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT); @@ -99,7 +152,7 @@ public final class StringUtils { result.add(element); } } - return TextUtils.join(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT, result); + return join(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT, result); } /** @@ -117,7 +170,7 @@ public final class StringUtils { // Compare each suggestion with each previous suggestion for (int j = 0; j < i; j++) { final String previous = suggestions.get(j); - if (TextUtils.equals(cur, previous)) { + if (equals(cur, previous)) { suggestions.remove(i); i--; break; @@ -471,7 +524,7 @@ public final class StringUtils { */ @UsedForTesting public static byte[] hexStringToByteArray(final String hexString) { - if (TextUtils.isEmpty(hexString)) { + if (isEmpty(hexString)) { return null; } final int N = hexString.length(); @@ -512,67 +565,15 @@ public final class StringUtils { return lastIndex - i; } - /** - * Splits the given {@code charSequence} with at occurrences of the given {@code regex}. - * <p> - * This is equivalent to - * {@code charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0)} - * except that the spans are preserved in the result array. - * </p> - * @param charSequence the character sequence to be split. - * @param regex the regex pattern to be used as the separator. - * @param preserveTrailingEmptySegments {@code true} to preserve the trailing empty - * segments. Otherwise, trailing empty segments will be removed before being returned. - * @return the array which contains the result. All the spans in the <code>charSequence</code> - * is preserved. - */ - @UsedForTesting - public static CharSequence[] split(final CharSequence charSequence, final String regex, - final boolean preserveTrailingEmptySegments) { - // A short-cut for non-spanned strings. - if (!(charSequence instanceof Spanned)) { - // -1 means that trailing empty segments will be preserved. - return charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0); - } - - // Hereafter, emulate String.split for CharSequence. - final ArrayList<CharSequence> sequences = new ArrayList<>(); - final Matcher matcher = Pattern.compile(regex).matcher(charSequence); - int nextStart = 0; - boolean matched = false; - while (matcher.find()) { - sequences.add(charSequence.subSequence(nextStart, matcher.start())); - nextStart = matcher.end(); - matched = true; - } - if (!matched) { - // never matched. preserveTrailingEmptySegments is ignored in this case. - return new CharSequence[] { charSequence }; - } - sequences.add(charSequence.subSequence(nextStart, charSequence.length())); - if (!preserveTrailingEmptySegments) { - for (int i = sequences.size() - 1; i >= 0; --i) { - if (!TextUtils.isEmpty(sequences.get(i))) { - break; - } - sequences.remove(i); - } - } - return sequences.toArray(new CharSequence[sequences.size()]); - } - - @UsedForTesting public static class Stringizer<E> { public String stringize(final E element) { return element != null ? element.toString() : "null"; } - @UsedForTesting public final String join(final E[] array) { return joinStringArray(toStringArray(array), null /* delimiter */); } - @UsedForTesting public final String join(final E[] array, final String delimiter) { return joinStringArray(toStringArray(array), delimiter); } @@ -606,9 +607,8 @@ public final class StringUtils { * @param text the text to be examined. * @return {@code true} if the last composed word contains line-breaking separator. */ - @UsedForTesting public static boolean hasLineBreakCharacter(final String text) { - if (TextUtils.isEmpty(text)) { + if (isEmpty(text)) { return false; } for (int i = text.length() - 1; i >= 0; --i) { diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 817bb5187..08d8bb260 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -39,6 +39,8 @@ <item>hi_ZZ</item> <item>sr_ZZ</item> </string-array> + <string name="subtype_in_root_locale_hi_ZZ">Hinglish</string> + <string name="subtype_in_root_locale_sr_ZZ">Srpski</string> <!-- Generic subtype label --> <string name="subtype_generic">%s</string> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 583c3b123..e1a72c476 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -214,8 +214,7 @@ <!-- Description for Hinglish (https://en.wikipedia.org/wiki/Hinglish) keyboard subtype [CHAR LIMIT=25] --> <string name="subtype_hi_ZZ">Hinglish</string> <!-- Description for Serbian (Latin) keyboard subtype [CHAR LIMIT=25] - (Latin) can be an abbreviation to fit in the CHAR LIMIT. - Note for Serbian translator: this should be translated with Latin script and (Latin) should be omitted. --> + (Latin) can be an abbreviation to fit in the CHAR LIMIT. --> <string name="subtype_sr_ZZ">Serbian (Latin)</string> <!-- Description for English (UK) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. @@ -233,16 +232,14 @@ This should be identical to subtype_hi_ZZ aside from the trailing (%s). --> <string name="subtype_with_layout_hi_ZZ">Hinglish (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> <!-- Description for Serbian (Latin) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] - This should be identical to subtype_sr_ZZ aside from the trailing (%s). - Note for Serbian translator: this should be translated with Latin script. --> + This should be identical to subtype_sr_ZZ aside from the trailing (%s). --> <string name="subtype_with_layout_sr_ZZ">Serbian (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> <!-- Description for "LANGUAGE_NAME" (Traditional) keyboard subtype [CHAR LIMIT=25] (Traditional) can be an abbreviation to fit in the CHAR LIMIT. --> <string name="subtype_generic_traditional"><xliff:g id="LANGUAGE_NAME" example="Nepali">%s</xliff:g> (Traditional)</string> <!-- Description for "LANGUAGE_NAME" (Compact) keyboard subtype [CHAR LIMIT=25] - (Compact) can be an abbreviation to fit in the CHAR LIMIT. - TODO: Remove translatable=false once we are settled down with the naming. --> - <string name="subtype_generic_compact" translatable="false"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string> + (Compact) can be an abbreviation to fit in the CHAR LIMIT. --> + <string name="subtype_generic_compact"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string> <!-- This string is displayed in a language list that allows to choose a language for suggestions in a software keyboard. This setting won't give suggestions in any particular language, hence "No language". diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index 9f7caa47e..bbda9f8e2 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -28,7 +28,7 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index 92bcda455..a1226dc93 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -19,7 +19,7 @@ package com.android.inputmethod.event; import com.android.inputmethod.annotations.ExternallyReferenced; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import javax.annotation.Nonnull; diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 04a0f1e13..6b2094b9e 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -38,7 +38,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardRow; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index e66523be0..f3aaaefbf 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -56,9 +56,9 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index abcfff8a6..f0de86ff9 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -24,7 +24,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; public final class MoreKeysKeyboard extends Keyboard { diff --git a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java index 5797b7efd..2e2ed52dd 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java @@ -17,7 +17,7 @@ package com.android.inputmethod.keyboard.internal; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import android.text.TextUtils; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index d33e53a61..63aab968b 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -20,7 +20,7 @@ import static com.android.inputmethod.latin.common.Constants.CODE_OUTPUT_TEXT; import static com.android.inputmethod.latin.common.Constants.CODE_UNSPECIFIED; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; /** * The string parser of the key specification. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 6c75fb6c1..c739bf3e0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -34,8 +34,8 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardTheme; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.ResourceUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.XmlParseUtils; import com.android.inputmethod.latin.utils.XmlParseUtils.ParseException; diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java index 4392dbcbd..a0bb406aa 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java @@ -22,9 +22,9 @@ import android.util.SparseIntArray; import com.android.inputmethod.compat.CharacterCompat; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 76459f817..1c4ff9659 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -24,6 +24,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; @@ -33,7 +34,6 @@ import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.WordInputEventForPersonalization; import java.io.File; diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 08e1983d4..59763c0fc 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -30,9 +30,9 @@ import android.util.Log; import com.android.inputmethod.annotations.ExternallyReferenced; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.personalization.AccountUtils; import com.android.inputmethod.latin.utils.ExecutorUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.io.File; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index 002222080..37effeead 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -24,8 +24,8 @@ import android.text.InputType; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.InputTypeUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/NgramContext.java b/java/src/com/android/inputmethod/latin/NgramContext.java index 0ccea4732..82a13274d 100644 --- a/java/src/com/android/inputmethod/latin/NgramContext.java +++ b/java/src/com/android/inputmethod/latin/NgramContext.java @@ -20,7 +20,7 @@ import android.text.TextUtils; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java index 93598d2fb..a65304cd0 100644 --- a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java +++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java @@ -18,7 +18,7 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.internal.KeySpecParser; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 0763ef807..834f747d9 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -35,6 +35,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.CapsModeUtils; @@ -42,7 +43,6 @@ import com.android.inputmethod.latin.utils.DebugLogUtils; import com.android.inputmethod.latin.utils.NgramContextUtils; import com.android.inputmethod.latin.utils.ScriptUtils; import com.android.inputmethod.latin.utils.SpannableStringUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import javax.annotation.Nonnull; diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 17df1eab4..bb7d24305 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -21,11 +21,11 @@ import android.text.TextUtils; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SuggestionResults; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index a6428896e..b84de6919 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -21,8 +21,8 @@ import android.view.inputmethod.CompletionInfo; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 8830521c7..35436f59c 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -20,9 +20,9 @@ import com.android.inputmethod.event.CombinerChain; import com.android.inputmethod.event.Event; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Collections; diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index a67f46108..f3a287320 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -52,6 +52,7 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; @@ -61,7 +62,6 @@ import com.android.inputmethod.latin.utils.AsyncResultHolder; import com.android.inputmethod.latin.utils.InputTypeUtils; import com.android.inputmethod.latin.utils.RecapitalizeStatus; import com.android.inputmethod.latin.utils.StatsUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java index e7808e46e..388d57816 100644 --- a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java +++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java @@ -21,8 +21,8 @@ import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.NgramContext.WordInfo; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.CombinedFormatUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 6d23fcb66..19db60655 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -29,11 +29,11 @@ import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.StatsUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.Collections; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java index 46aef89c4..70d97a5ba 100644 --- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java +++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java @@ -23,7 +23,7 @@ import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java index ac395bf02..2c690aea7 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java @@ -28,7 +28,7 @@ import android.view.textservice.TextInfo; import com.android.inputmethod.compat.TextInfoCompatUtils; import com.android.inputmethod.latin.NgramContext; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.SpannableStringUtils; import java.util.ArrayList; import java.util.Locale; @@ -71,9 +71,10 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck if (!subText.toString().contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { continue; } - final CharSequence[] splitTexts = StringUtils.split(subText, + // Split preserving spans. + final CharSequence[] splitTexts = SpannableStringUtils.split(subText, AndroidSpellCheckerService.SINGLE_QUOTE, - true /* preserveTrailingEmptySegments */ ); + true /* preserveTrailingEmptySegments */); if (splitTexts == null || splitTexts.length <= 1) { continue; } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 514bfca85..3ad8fb910 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -34,11 +34,11 @@ import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.ScriptUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SuggestionResults; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java index 02ace6a1e..2aac7c57a 100644 --- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java @@ -31,6 +31,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.common.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java index ce25fe6a4..23ffde2a2 100644 --- a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.personalization.PersonalizationHelper; diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java index b087e9ee8..0db63fd9f 100644 --- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java @@ -21,6 +21,7 @@ import android.text.TextUtils; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java index 8f0f9bb44..56c8249bd 100644 --- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java @@ -40,6 +40,7 @@ import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; /** diff --git a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java index e3cac97f0..21daddce7 100644 --- a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java +++ b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin.utils; +import com.android.inputmethod.latin.common.StringUtils; + import java.util.Locale; /** diff --git a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java index cea1d1d58..c41817fe6 100644 --- a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java @@ -24,6 +24,12 @@ import android.text.TextUtils; import android.text.style.SuggestionSpan; import android.text.style.URLSpan; +import com.android.inputmethod.annotations.UsedForTesting; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public final class SpannableStringUtils { /** * Copies the spans from the region <code>start...end</code> in @@ -125,4 +131,53 @@ public final class SpannableStringUtils { final URLSpan[] spans = spanned.getSpans(startIndex - 1, endIndex + 1, URLSpan.class); return null != spans && spans.length > 0; } + + /** + * Splits the given {@code charSequence} with at occurrences of the given {@code regex}. + * <p> + * This is equivalent to + * {@code charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0)} + * except that the spans are preserved in the result array. + * </p> + * @param charSequence the character sequence to be split. + * @param regex the regex pattern to be used as the separator. + * @param preserveTrailingEmptySegments {@code true} to preserve the trailing empty + * segments. Otherwise, trailing empty segments will be removed before being returned. + * @return the array which contains the result. All the spans in the <code>charSequence</code> + * is preserved. + */ + @UsedForTesting + public static CharSequence[] split(final CharSequence charSequence, final String regex, + final boolean preserveTrailingEmptySegments) { + // A short-cut for non-spanned strings. + if (!(charSequence instanceof Spanned)) { + // -1 means that trailing empty segments will be preserved. + return charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0); + } + + // Hereafter, emulate String.split for CharSequence. + final ArrayList<CharSequence> sequences = new ArrayList<>(); + final Matcher matcher = Pattern.compile(regex).matcher(charSequence); + int nextStart = 0; + boolean matched = false; + while (matcher.find()) { + sequences.add(charSequence.subSequence(nextStart, matcher.start())); + nextStart = matcher.end(); + matched = true; + } + if (!matched) { + // never matched. preserveTrailingEmptySegments is ignored in this case. + return new CharSequence[] { charSequence }; + } + sequences.add(charSequence.subSequence(nextStart, charSequence.length())); + if (!preserveTrailingEmptySegments) { + for (int i = sequences.size() - 1; i >= 0; --i) { + if (!TextUtils.isEmpty(sequences.get(i))) { + break; + } + sequences.remove(i); + } + } + return sequences.toArray(new CharSequence[sequences.size()]); + } } diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index eb85c1baf..55c1dc9e5 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -28,10 +28,10 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodSubtype; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.Locale; /** @@ -59,7 +59,8 @@ public final class SubtypeLocaleUtils { // Keyboard layout to subtype name resource id map. private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap = new HashMap<>(); // Exceptional locale whose name should be displayed in Locale.ROOT. - static final HashSet<String> sExceptionalLocaleDisplayedInRootLocale = new HashSet<>(); + private static final HashMap<String, Integer> sExceptionalLocaleDisplayedInRootLocale = + new HashMap<>(); // Exceptional locale to subtype name resource id map. private static final HashMap<String, Integer> sExceptionalLocaleToNameIdsMap = new HashMap<>(); // Exceptional locale to subtype name with layout resource id map. @@ -73,6 +74,8 @@ public final class SubtypeLocaleUtils { "string/subtype_with_layout_"; private static final String SUBTYPE_NAME_RESOURCE_NO_LANGUAGE_PREFIX = "string/subtype_no_language_"; + private static final String SUBTYPE_NAME_RESOURCE_IN_ROOT_LOCALE_PREFIX = + "string/subtype_in_root_locale_"; // Keyboard layout set name for the subtypes that don't have a keyboardLayoutSet extra value. // This is for compatibility to keep the same subtype ids as pre-JellyBean. private static final HashMap<String, String> sLocaleAndExtraValueToKeyboardLayoutSetMap = @@ -117,7 +120,10 @@ public final class SubtypeLocaleUtils { final String[] exceptionalLocaleInRootLocale = res.getStringArray( R.array.subtype_locale_displayed_in_root_locale); for (int i = 0; i < exceptionalLocaleInRootLocale.length; i++) { - sExceptionalLocaleDisplayedInRootLocale.add(exceptionalLocaleInRootLocale[i]); + final String localeString = exceptionalLocaleInRootLocale[i]; + final String resourceName = SUBTYPE_NAME_RESOURCE_IN_ROOT_LOCALE_PREFIX + localeString; + final int resId = res.getIdentifier(resourceName, null, RESOURCE_PACKAGE_NAME); + sExceptionalLocaleDisplayedInRootLocale.put(localeString, resId); } final String[] exceptionalLocales = res.getStringArray( @@ -171,7 +177,7 @@ public final class SubtypeLocaleUtils { if (NO_LANGUAGE.equals(localeString)) { return sResources.getConfiguration().locale; } - if (sExceptionalLocaleDisplayedInRootLocale.contains(localeString)) { + if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { return Locale.ROOT; } return LocaleUtils.constructLocaleFromString(localeString); @@ -190,7 +196,7 @@ public final class SubtypeLocaleUtils { public static String getSubtypeLanguageDisplayName(final String localeString) { final Locale displayLocale = getDisplayLocaleOfSubtypeLocale(localeString); final String languageString; - if (sExceptionalLocaleDisplayedInRootLocale.contains(localeString)) { + if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { languageString = localeString; } else { final Locale locale = LocaleUtils.constructLocaleFromString(localeString); @@ -205,7 +211,16 @@ public final class SubtypeLocaleUtils { // No language subtype should be displayed in system locale. return sResources.getString(R.string.subtype_no_language); } - final Integer exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString); + final Integer exceptionalNameResId; + if (displayLocale.equals(Locale.ROOT) + && sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { + exceptionalNameResId = sExceptionalLocaleDisplayedInRootLocale.get(localeString); + } else if (sExceptionalLocaleToNameIdsMap.containsKey(localeString)) { + exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString); + } else { + exceptionalNameResId = null; + } + final String displayName; if (exceptionalNameResId != null) { final RunInLocale<String> getExceptionalName = new RunInLocale<String>() { diff --git a/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java b/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java index d3fa0c748..86a5b19ec 100644 --- a/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java +++ b/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java @@ -21,6 +21,7 @@ import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.DistracterFilter.HandlingType; diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp index a06e7d070..450203d98 100644 --- a/native/jni/src/suggest/core/policy/weighting.cpp +++ b/native/jni/src/suggest/core/policy/weighting.cpp @@ -119,7 +119,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n return weighting->getSubstitutionCost() + weighting->getMatchedCost(traverseSession, dicNode, inputStateG); case CT_NEW_WORD_SPACE_OMISSION: - return weighting->getNewWordSpatialCost(traverseSession, dicNode, inputStateG); + return weighting->getSpaceOmissionCost(traverseSession, dicNode, inputStateG); case CT_MATCH: return weighting->getMatchedCost(traverseSession, dicNode, inputStateG); case CT_COMPLETION: diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h index bd6b3cf41..863c4eabe 100644 --- a/native/jni/src/suggest/core/policy/weighting.h +++ b/native/jni/src/suggest/core/policy/weighting.h @@ -57,7 +57,7 @@ class Weighting { const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0; - virtual float getNewWordSpatialCost(const DicTraverseSession *const traverseSession, + virtual float getSpaceOmissionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, DicNode_InputStateG *const inputStateG) const = 0; virtual float getNewWordBigramLanguageCost( diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp index c71526293..68a36454e 100644 --- a/native/jni/src/suggest/core/suggest.cpp +++ b/native/jni/src/suggest/core/suggest.cpp @@ -160,8 +160,7 @@ void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const { // TODO: Remove. Do not prune node here. const bool allowsErrorCorrections = TRAVERSAL->allowsErrorCorrections(&dicNode); // Process for handling space substitution (e.g., hevis => he is) - if (allowsErrorCorrections - && TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) { + if (TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) { createNextWordDicNode(traverseSession, &dicNode, true /* spaceSubstitution */); } diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp index 6a2db687d..a6f9a8b23 100644 --- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp @@ -48,17 +48,17 @@ const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.5508f; const float ScoringParams::INSERTION_COST_PROXIMITY_CHAR = 0.674f; const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.639f; const float ScoringParams::TRANSPOSITION_COST = 0.5608f; -const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.334f; +const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.33f; +const float ScoringParams::SPACE_OMISSION_COST = 0.1f; const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.37972f; const float ScoringParams::SUBSTITUTION_COST = 0.3806f; -const float ScoringParams::COST_NEW_WORD = 0.0314f; const float ScoringParams::COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE = 0.3224f; const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.1214f; const float ScoringParams::COST_FIRST_COMPLETION = 0.4836f; const float ScoringParams::COST_COMPLETION = 0.00624f; const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.0683f; const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.0362f; -const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.4182f; +const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.3482f; const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f; const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f; const float ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT = 0.095f; diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h index 731424f3d..b8f889559 100644 --- a/native/jni/src/suggest/policyimpl/typing/scoring_params.h +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h @@ -56,9 +56,9 @@ class ScoringParams { static const float INSERTION_COST_FIRST_CHAR; static const float TRANSPOSITION_COST; static const float SPACE_SUBSTITUTION_COST; + static const float SPACE_OMISSION_COST; static const float ADDITIONAL_PROXIMITY_COST; static const float SUBSTITUTION_COST; - static const float COST_NEW_WORD; static const float COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE; static const float DISTANCE_WEIGHT_LANGUAGE; static const float COST_FIRST_COMPLETION; diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h index 84077174d..1338ac81a 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h @@ -150,9 +150,10 @@ class TypingWeighting : public Weighting { return cost + weightedDistance; } - float getNewWordSpatialCost(const DicTraverseSession *const traverseSession, + float getSpaceOmissionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, DicNode_InputStateG *inputStateG) const { - return ScoringParams::COST_NEW_WORD * traverseSession->getMultiWordCostMultiplier(); + const float cost = ScoringParams::SPACE_OMISSION_COST; + return cost * traverseSession->getMultiWordCostMultiplier(); } float getNewWordBigramLanguageCost(const DicTraverseSession *const traverseSession, @@ -202,7 +203,10 @@ class TypingWeighting : public Weighting { AK_FORCE_INLINE float getSpaceSubstitutionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { - const float cost = ScoringParams::SPACE_SUBSTITUTION_COST + ScoringParams::COST_NEW_WORD; + const int inputIndex = dicNode->getInputIndex(0); + const float distanceToSpaceKey = traverseSession->getProximityInfoState(0) + ->getPointToKeyLength(inputIndex, KEYCODE_SPACE); + const float cost = ScoringParams::SPACE_SUBSTITUTION_COST * distanceToSpaceKey; return cost * traverseSession->getMultiWordCostMultiplier(); } diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java index 2361968a1..0246c49a1 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java @@ -17,9 +17,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.content.SharedPreferences; import android.content.res.Resources; -import android.preference.PreferenceManager; import android.test.AndroidTestCase; import android.view.ContextThemeWrapper; import android.view.inputmethod.EditorInfo; @@ -62,8 +60,8 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { } }; - private SharedPreferences mSharedPreferences; - private String mSavedAdditionalSubtypes; + private RichInputMethodManager mRichImm; + private InputMethodSubtype[] mSavedAdditionalSubtypes; private int mScreenMetrics; protected abstract int getKeyboardThemeForTests(); @@ -72,15 +70,17 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); - mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); final Resources res = context.getResources(); + RichInputMethodManager.init(context); + mRichImm = RichInputMethodManager.getInstance(); - // Save additional subtypes preference. - mSavedAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(mSharedPreferences, res); - final String predefinedSubtypes = AdditionalSubtypeUtils.createPrefSubtypes( - res.getStringArray(R.array.predefined_subtypes)); - // Reset additional subtypes to predefined ones. - Settings.writePrefAdditionalSubtypes(mSharedPreferences, predefinedSubtypes); + // Save and reset additional subtypes preference. + mSavedAdditionalSubtypes = mRichImm.getAdditionalSubtypes(context); + final InputMethodSubtype[] predefinedAdditionalSubtypes = + AdditionalSubtypeUtils.createAdditionalSubtypesArray( + AdditionalSubtypeUtils.createPrefSubtypes( + res.getStringArray(R.array.predefined_subtypes))); + mRichImm.setAdditionalInputMethodSubtypes(predefinedAdditionalSubtypes); final KeyboardTheme keyboardTheme = KeyboardTheme.searchKeyboardThemeById( getKeyboardThemeForTests(), KeyboardTheme.KEYBOARD_THEMES); @@ -88,10 +88,8 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { KeyboardLayoutSet.onKeyboardThemeChanged(); mScreenMetrics = Settings.readScreenMetrics(res); - RichInputMethodManager.init(context); - final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); - final InputMethodInfo imi = richImm.getInputMethodInfoOfThisIme(); + final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); final int subtypeCount = imi.getSubtypeCount(); for (int index = 0; index < subtypeCount; index++) { mAllSubtypesList.add(imi.getSubtypeAt(index)); @@ -101,7 +99,7 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { @Override protected void tearDown() throws Exception { // Restore additional subtypes preference. - Settings.writePrefAdditionalSubtypes(mSharedPreferences, mSavedAdditionalSubtypes); + mRichImm.setAdditionalInputMethodSubtypes(mSavedAdditionalSubtypes); super.tearDown(); } diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java index a6aac3583..afc5448a3 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java @@ -20,7 +20,7 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.ArrayList; import java.util.List; diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java index 0547ea31b..9bb5f187a 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java @@ -19,7 +19,7 @@ package com.android.inputmethod.keyboard.layout.expected; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Locale; diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 7d356a4be..c76f6f446 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -674,10 +674,15 @@ public class InputLogicTests extends InputTestsBase { mEditText.getText().toString()); } - private void typeWordAndPutCursorInside(final String word, final int startPos) { + private void typeOrGestureWordAndPutCursorInside(final boolean gesture, final String word, + final int startPos) { final int END_OF_WORD = startPos + word.length(); final int NEW_CURSOR_POSITION = startPos + word.length() / 2; - type(word); + if (gesture) { + gesture(word); + } else { + type(word); + } sendUpdateForCursorMoveTo(END_OF_WORD); runMessages(); sendUpdateForCursorMoveTo(NEW_CURSOR_POSITION); @@ -687,6 +692,14 @@ public class InputLogicTests extends InputTestsBase { startPos, END_OF_WORD); } + private void typeWordAndPutCursorInside(final String word, final int startPos) { + typeOrGestureWordAndPutCursorInside(false /* gesture */, word, startPos); + } + + private void gestureWordAndPutCursorInside(final String word, final int startPos) { + typeOrGestureWordAndPutCursorInside(true /* gesture */, word, startPos); + } + private void ensureComposingSpanPos(final String message, final int from, final int to) { assertEquals(message, from, BaseInputConnection.getComposingSpanStart(mEditText.getText())); assertEquals(message, to, BaseInputConnection.getComposingSpanEnd(mEditText.getText())); @@ -703,6 +716,23 @@ public class InputLogicTests extends InputTestsBase { int cursorPos = sendUpdateForCursorMoveToEndOfLine(); runMessages(); type(" "); + assertEquals("mbo", "some thing ", mEditText.getText().toString()); + typeWordAndPutCursorInside(WORD_TO_TYPE, cursorPos + 1 /* startPos */); + type(Constants.CODE_DELETE); + ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1); + } + + public void testTypeWithinGestureComposing() { + final String WORD_TO_TYPE = "something"; + final String EXPECTED_RESULT = "some thing"; + gestureWordAndPutCursorInside(WORD_TO_TYPE, 0 /* startPos */); + type(" "); + ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1); + assertEquals("space in the middle of a composing word", EXPECTED_RESULT, + mEditText.getText().toString()); + int cursorPos = sendUpdateForCursorMoveToEndOfLine(); + runMessages(); + type(" "); typeWordAndPutCursorInside(WORD_TO_TYPE, cursorPos + 1 /* startPos */); type(Constants.CODE_DELETE); ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1); diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index 78b4b18ec..161336aa6 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -43,10 +43,10 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.Dictionary.PhonyDictionary; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.LocaleUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Locale; diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java index 34c26004b..bcf016ae9 100644 --- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java +++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java @@ -31,11 +31,11 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.NgramContextUtils; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.ScriptUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import java.util.Locale; diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java index 8f5e8f7e5..20256e670 100644 --- a/tests/src/com/android/inputmethod/latin/WordComposerTests.java +++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java @@ -20,8 +20,8 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StringUtils; /** * Unit tests for WordComposer. diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java index e6131cf65..83afd782d 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java @@ -23,6 +23,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.RichInputMethodSubtype; @@ -36,6 +37,7 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { private RichInputMethodManager mRichImm; private Resources mRes; + private InputMethodSubtype mSavedAddtionalSubtypes[]; RichInputMethodSubtype EN_US; RichInputMethodSubtype EN_GB; @@ -45,6 +47,8 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { RichInputMethodSubtype FR_CH; RichInputMethodSubtype DE; RichInputMethodSubtype DE_CH; + RichInputMethodSubtype HI; + RichInputMethodSubtype SR; RichInputMethodSubtype ZZ; RichInputMethodSubtype DE_QWERTY; RichInputMethodSubtype FR_QWERTZ; @@ -54,17 +58,27 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { RichInputMethodSubtype ZZ_AZERTY; RichInputMethodSubtype ZZ_PC; - // This is a preliminary subtype and may not exist. - RichInputMethodSubtype HI_LATN; + // These are preliminary subtypes and may not exist. + RichInputMethodSubtype HI_LATN; // Hinglish + RichInputMethodSubtype SR_LATN; // Serbian Latin + RichInputMethodSubtype HI_LATN_DVORAK; + RichInputMethodSubtype SR_LATN_QWERTY; @Override protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); + mRes = context.getResources(); RichInputMethodManager.init(context); mRichImm = RichInputMethodManager.getInstance(); - mRes = context.getResources(); - SubtypeLocaleUtils.init(context); + + // Save and reset additional subtypes + mSavedAddtionalSubtypes = mRichImm.getAdditionalSubtypes(context); + final InputMethodSubtype[] predefinedAddtionalSubtypes = + AdditionalSubtypeUtils.createAdditionalSubtypesArray( + AdditionalSubtypeUtils.createPrefSubtypes( + mRes.getStringArray(R.array.predefined_subtypes))); + mRichImm.setAdditionalInputMethodSubtypes(predefinedAddtionalSubtypes); final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); final int subtypeCount = imi.getSubtypeCount(); @@ -89,6 +103,10 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { Locale.GERMAN.toString(), "qwertz")); DE_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( "de_CH", "swiss")); + HI = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "hi", "hindi")); + SR = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "sr", "south_slavic")); ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty")); DE_QWERTY = new RichInputMethodSubtype( @@ -117,9 +135,27 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { "hi_ZZ", "qwerty"); if (hiLatn != null) { HI_LATN = new RichInputMethodSubtype(hiLatn); + HI_LATN_DVORAK = new RichInputMethodSubtype( + AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "hi_ZZ", "dvorak")); + } + final InputMethodSubtype srLatn = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "sr_ZZ", "serbian_qwertz"); + if (srLatn != null) { + SR_LATN = new RichInputMethodSubtype(srLatn); + SR_LATN_QWERTY = new RichInputMethodSubtype( + AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "sr_ZZ", "qwerty")); } } + @Override + protected void tearDown() throws Exception { + // Restore additional subtypes. + mRichImm.setAdditionalInputMethodSubtypes(mSavedAddtionalSubtypes); + super.tearDown(); + } + public void testAllFullDisplayNameForSpacebar() { for (final RichInputMethodSubtype subtype : mSubtypesList) { final String subtypeName = SubtypeLocaleUtils @@ -150,10 +186,11 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { continue; } final Locale locale = locales[0]; - if (SubtypeLocaleUtils.sExceptionalLocaleDisplayedInRootLocale.contains( - locale.toString())) { + final Locale displayLocale = SubtypeLocaleUtils.getDisplayLocaleOfSubtypeLocale( + locale.toString()); + if (Locale.ROOT.equals(displayLocale)) { // Skip test because the language part of this locale string doesn't represent - // the locale to be displayed on the spacebar (for example hi_ZZ and Hinglish). + // the locale to be displayed on the spacebar (for example Hinglish). continue; } final String spacebarText = subtype.getMiddleDisplayName(); @@ -162,30 +199,36 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { subtype.getRawSubtype()), spacebarText); } else { assertEquals(subtypeName, - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), + SubtypeLocaleUtils.getSubtypeLanguageDisplayName(locale.toString()), spacebarText); } } } // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Middle Full - // ------ ------- - --------- ---------------------- - // en_US qwerty F English English (US) exception - // en_GB qwerty F English English (UK) exception - // es_US spanish F Español Español (EE.UU.) exception - // fr azerty F Français Français - // fr_CA qwerty F Français Français (Canada) - // fr_CH swiss F Français Français (Suisse) - // de qwertz F Deutsch Deutsch - // de_CH swiss F Deutsch Deutsch (Schweiz) - // hi_ZZ qwerty F Hinglish Hinglish - // zz qwerty F QWERTY QWERTY - // fr qwertz T Français Français - // de qwerty T Deutsch Deutsch - // en_US azerty T English English (US) - // zz azerty T AZERTY AZERTY + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ -------------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss F Deutsch Deutsch (Schweiz) + // hi hindi F हिन्दी हिन्दी + // hi_ZZ qwerty F Hinglish Hinglish exception + // sr south_slavic F Српски Српски + // sr_ZZ serbian_qwertz F Srpski Srpski exception + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // en_GB dvorak T English English (UK) + // hi_ZZ dvorak T Hinglish Hinglish exception + // sr_ZZ qwerty T Srpski Srpski exception + // zz azerty T AZERTY AZERTY private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() { @Override @@ -198,11 +241,9 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "Français (Suisse)", FR_CH.getFullDisplayName()); assertEquals("de", "Deutsch", DE.getFullDisplayName()); assertEquals("de_CH", "Deutsch (Schweiz)", DE_CH.getFullDisplayName()); + assertEquals("hi", "हिन्दी", HI.getFullDisplayName()); + assertEquals("sr", "Српски", SR.getFullDisplayName()); assertEquals("zz", "QWERTY", ZZ.getFullDisplayName()); - // This is a preliminary subtype and may not exist. - if (HI_LATN != null) { - assertEquals("hi_ZZ", "Hinglish", HI_LATN.getFullDisplayName()); - } assertEquals("en_US", "English", EN_US.getMiddleDisplayName()); assertEquals("en_GB", "English", EN_GB.getMiddleDisplayName()); @@ -213,10 +254,16 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("de", "Deutsch", DE.getMiddleDisplayName()); assertEquals("de_CH", "Deutsch", DE_CH.getMiddleDisplayName()); assertEquals("zz", "QWERTY", ZZ.getMiddleDisplayName()); - // This is a preliminary subtype and may not exist. + + // These are preliminary subtypes and may not exist. if (HI_LATN != null) { + assertEquals("hi_ZZ", "Hinglish", HI_LATN.getFullDisplayName()); assertEquals("hi_ZZ", "Hinglish", HI_LATN.getMiddleDisplayName()); } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "Srpski", SR_LATN.getFullDisplayName()); + assertEquals("sr_ZZ", "Srpski", SR_LATN.getMiddleDisplayName()); + } return null; } }; @@ -239,6 +286,16 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("es_US colemak", "Español", ES_US_COLEMAK.getMiddleDisplayName()); assertEquals("zz azerty", "AZERTY", ZZ_AZERTY.getMiddleDisplayName()); assertEquals("zz pc", "PC", ZZ_PC.getMiddleDisplayName()); + + // These are preliminary subtypes and may not exist. + if (HI_LATN_DVORAK != null) { + assertEquals("hi_ZZ dvorak", "Hinglish", HI_LATN_DVORAK.getFullDisplayName()); + assertEquals("hi_ZZ dvorak", "Hinglish", HI_LATN_DVORAK.getMiddleDisplayName()); + } + if (SR_LATN_QWERTY != null) { + assertEquals("sr_ZZ qwerty", "Srpski", SR_LATN_QWERTY.getFullDisplayName()); + assertEquals("sr_ZZ qwerty", "Srpski", SR_LATN_QWERTY.getMiddleDisplayName()); + } return null; } }; diff --git a/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java index 7d9d39959..0389fefb0 100644 --- a/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java @@ -23,6 +23,8 @@ import android.text.Spanned; import android.text.SpannedString; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.utils.SpannableStringUtils; import java.util.Arrays; import java.util.List; @@ -375,9 +377,9 @@ public class StringAndJsonUtilsTests extends AndroidTestCase { spannableString.setSpan(span1, 0, 7, SPAN1_FLAGS); spannableString.setSpan(span2, 0, 5, SPAN2_FLAGS); spannableString.setSpan(span3, 12, 13, SPAN3_FLAGS); - final CharSequence[] charSequencesFromSpanned = StringUtils.split( + final CharSequence[] charSequencesFromSpanned = SpannableStringUtils.split( spannableString, " ", true /* preserveTrailingEmptySegmengs */); - final CharSequence[] charSequencesFromString = StringUtils.split( + final CharSequence[] charSequencesFromString = SpannableStringUtils.split( spannableString.toString(), " ", true /* preserveTrailingEmptySegmengs */); @@ -456,44 +458,44 @@ public class StringAndJsonUtilsTests extends AndroidTestCase { } public void testSplitCharSequencePreserveTrailingEmptySegmengs() { - assertEquals(1, StringUtils.split("", " ", + assertEquals(1, SpannableStringUtils.split("", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(1, StringUtils.split(new SpannedString(""), " ", + assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(1, StringUtils.split("", " ", + assertEquals(1, SpannableStringUtils.split("", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(1, StringUtils.split(new SpannedString(""), " ", + assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(0, StringUtils.split(" ", " ", + assertEquals(0, SpannableStringUtils.split(" ", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(0, StringUtils.split(new SpannedString(" "), " ", + assertEquals(0, SpannableStringUtils.split(new SpannedString(" "), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(2, StringUtils.split(" ", " ", + assertEquals(2, SpannableStringUtils.split(" ", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(2, StringUtils.split(new SpannedString(" "), " ", + assertEquals(2, SpannableStringUtils.split(new SpannedString(" "), " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(3, StringUtils.split("a b c ", " ", + assertEquals(3, SpannableStringUtils.split("a b c ", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(3, StringUtils.split(new SpannedString("a b c "), " ", + assertEquals(3, SpannableStringUtils.split(new SpannedString("a b c "), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(5, StringUtils.split("a b c ", " ", + assertEquals(5, SpannableStringUtils.split("a b c ", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(5, StringUtils.split(new SpannedString("a b c "), " ", + assertEquals(5, SpannableStringUtils.split(new SpannedString("a b c "), " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(6, StringUtils.split("a b ", " ", + assertEquals(6, SpannableStringUtils.split("a b ", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(6, StringUtils.split(new SpannedString("a b "), " ", + assertEquals(6, SpannableStringUtils.split(new SpannedString("a b "), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(7, StringUtils.split("a b ", " ", + assertEquals(7, SpannableStringUtils.split("a b ", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(7, StringUtils.split(new SpannedString("a b "), " ", + assertEquals(7, SpannableStringUtils.split(new SpannedString("a b "), " ", true /* preserveTrailingEmptySegmengs */).length); } } diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index dfc3fecfd..54f478f5a 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -23,6 +23,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.RichInputMethodSubtype; @@ -36,6 +37,7 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { private RichInputMethodManager mRichImm; private Resources mRes; + private InputMethodSubtype mSavedAddtionalSubtypes[]; InputMethodSubtype EN_US; InputMethodSubtype EN_GB; @@ -45,6 +47,8 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype FR_CH; InputMethodSubtype DE; InputMethodSubtype DE_CH; + InputMethodSubtype HI; + InputMethodSubtype SR; InputMethodSubtype ZZ; InputMethodSubtype DE_QWERTY; InputMethodSubtype FR_QWERTZ; @@ -54,17 +58,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype ZZ_AZERTY; InputMethodSubtype ZZ_PC; - // This is a preliminary subtype and may not exist. - InputMethodSubtype HI_LATN; + // These are preliminary subtypes and may not exist. + InputMethodSubtype HI_LATN; // Hinglish + InputMethodSubtype SR_LATN; // Serbian Latin + InputMethodSubtype HI_LATN_DVORAK; // Hinglis Dvorak + InputMethodSubtype SR_LATN_QWERTY; // Serbian Latin Qwerty @Override protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); + mRes = context.getResources(); RichInputMethodManager.init(context); mRichImm = RichInputMethodManager.getInstance(); - mRes = context.getResources(); - SubtypeLocaleUtils.init(context); + + // Save and reset additional subtypes + mSavedAddtionalSubtypes = mRichImm.getAdditionalSubtypes(context); + final InputMethodSubtype[] predefinedAddtionalSubtypes = + AdditionalSubtypeUtils.createAdditionalSubtypesArray( + AdditionalSubtypeUtils.createPrefSubtypes( + mRes.getStringArray(R.array.predefined_subtypes))); + mRichImm.setAdditionalInputMethodSubtypes(predefinedAddtionalSubtypes); final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); final int subtypeCount = imi.getSubtypeCount(); @@ -89,6 +103,10 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { Locale.GERMAN.toString(), "qwertz"); DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( "de_CH", "swiss"); + HI = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "hi", "hindi"); + SR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "sr", "south_slavic"); ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( @@ -107,6 +125,22 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty"); HI_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("hi_ZZ", "qwerty"); + if (HI_LATN != null) { + HI_LATN_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "hi_ZZ", "dvorak"); + } + SR_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("sr_ZZ", "serbian_qwertz"); + if (SR_LATN != null) { + SR_LATN_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "sr_ZZ", "qwerty"); + } + } + + @Override + protected void tearDown() throws Exception { + // Restore additional subtypes. + mRichImm.setAdditionalInputMethodSubtypes(mSavedAddtionalSubtypes); + super.tearDown(); } public void testAllFullDisplayName() { @@ -139,11 +173,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH)); assertEquals("de", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH)); + assertEquals("hi", "hindi", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI)); + assertEquals("sr", "south_slavic", SubtypeLocaleUtils.getKeyboardLayoutSetName(SR)); assertEquals("zz", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); - // This is a preliminary subtype and may not exist. - if (HI_LATN != null) { - assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN)); - } assertEquals("de qwerty", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_QWERTY)); assertEquals("fr qwertz", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_QWERTZ)); @@ -155,28 +187,46 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US_COLEMAK)); assertEquals("zz azerty", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ_AZERTY)); + + // These are preliminary subtypes and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN)); + assertEquals("hi_ZZ dvorak", "dvorak", + SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN_DVORAK)); + } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "serbian_qwertz", + SubtypeLocaleUtils.getKeyboardLayoutSetName(SR_LATN)); + assertEquals("sr_ZZ qwerty", "qwerty", + SubtypeLocaleUtils.getKeyboardLayoutSetName(SR_LATN_QWERTY)); + } } // InputMethodSubtype's display name in system locale (en_US). - // isAdditionalSubtype (T=true, F=false) - // locale layout | display name - // ------ ------- - ---------------------- - // en_US qwerty F English (US) exception - // en_GB qwerty F English (UK) exception - // es_US spanish F Spanish (US) exception - // fr azerty F French - // fr_CA qwerty F French (Canada) - // fr_CH swiss F French (Switzerland) - // de qwertz F German - // de_CH swiss F German (Switzerland) - // hi_ZZ qwerty F Hinglish - // zz qwerty F Alphabet (QWERTY) - // fr qwertz T French (QWERTZ) - // de qwerty T German (QWERTY) - // en_US azerty T English (US) (AZERTY) exception - // en_UK dvorak T English (UK) (Dvorak) exception - // es_US colemak T Spanish (US) (Colemak) exception - // zz pc T Alphabet (PC) + // isAdditionalSubtype (T=true, F=false) + // locale layout | display name + // ------ -------------- - ---------------------- + // en_US qwerty F English (US) exception + // en_GB qwerty F English (UK) exception + // es_US spanish F Spanish (US) exception + // fr azerty F French + // fr_CA qwerty F French (Canada) + // fr_CH swiss F French (Switzerland) + // de qwertz F German + // de_CH swiss F German (Switzerland) + // hi hindi F Hindi + // hi_ZZ qwerty F Hinglish exception + // sr south_slavic F Serbian + // sr_ZZ serbian_qwertz F Serbian (Latin) exception + // zz qwerty F Alphabet (QWERTY) + // fr qwertz T French (QWERTZ) + // de qwerty T German (QWERTY) + // en_US azerty T English (US) (AZERTY) exception + // en_UK dvorak T English (UK) (Dvorak) exception + // es_US colemak T Spanish (US) (Colemak) exception + // hi_ZZ dvorak T Hinglish (Dvorka) exception + // sr_ZZ qwerty T Serbian (QWERTY) exception + // zz pc T Alphabet (PC) public void testPredefinedSubtypesInEnglishSystemLocale() { final RunInLocale<Void> tests = new RunInLocale<Void>() { @@ -198,13 +248,21 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "German (Switzerland)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); + assertEquals("hi", "Hindi", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI)); + assertEquals("sr", "Serbian", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR)); assertEquals("zz", "Alphabet (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); - // This is a preliminary subtype and may not exist. + // These are preliminary subtypes and may not exist. if (HI_LATN != null) { assertEquals("hi_ZZ", "Hinglish", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "Serbian (Latin)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN)); + } return null; } }; @@ -229,6 +287,15 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); assertEquals("zz pc", "Alphabet (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); + // These are preliminary subtypes and may not exist. + if (HI_LATN_DVORAK != null) { + assertEquals("hi_ZZ", "Hinglish (Dvorak)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK)); + } + if (SR_LATN_QWERTY != null) { + assertEquals("sr_ZZ", "Serbian (QWERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY)); + } return null; } }; @@ -239,22 +306,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // isAdditionalSubtype (T=true, F=false) // locale layout | display name // ------ ------- - ---------------------- - // en_US qwerty F Anglais (États-Unis) exception - // en_GB qwerty F Anglais (Royaume-Uni) exception - // es_US spanish F Espagnol (États-Unis) exception - // fr azerty F Français - // fr_CA qwerty F Français (Canada) - // fr_CH swiss F Français (Suisse) - // de qwertz F Allemand - // de_CH swiss F Allemand (Suisse) - // hi_ZZ qwerty F Hinglish - // zz qwerty F Alphabet latin (QWERTY) - // fr qwertz T Français (QWERTZ) - // de qwerty T Allemand (QWERTY) - // en_US azerty T Anglais (États-Unis) (AZERTY) exception - // en_UK dvorak T Anglais (Royaume-Uni) (Dvorak) exception - // es_US colemak T Espagnol (États-Unis) (Colemak) exception - // zz pc T Alphabet latin (PC) + // en_US qwerty F Anglais (États-Unis) exception + // en_GB qwerty F Anglais (Royaume-Uni) exception + // es_US spanish F Espagnol (États-Unis) exception + // fr azerty F Français + // fr_CA qwerty F Français (Canada) + // fr_CH swiss F Français (Suisse) + // de qwertz F Allemand + // de_CH swiss F Allemand (Suisse) + // hi hindi F Hindi exception + // hi_ZZ qwerty F Hindi/Anglais exception + // sr south_slavic F Serbe exception + // sr_ZZ serbian_qwertz F Serbe (latin) exception + // zz qwerty F Alphabet latin (QWERTY) + // fr qwertz T Français (QWERTZ) + // de qwerty T Allemand (QWERTY) + // en_US azerty T Anglais (États-Unis) (AZERTY) exception + // en_UK dvorak T Anglais (Royaume-Uni) (Dvorak) exception + // es_US colemak T Espagnol (États-Unis) (Colemak) exception + // hi_ZZ dvorak T Hindi/Anglais (Dvorka) exception + // sr_ZZ qwerty T Serbe (QWERTY) exception + // zz pc T Alphabet latin (PC) public void testPredefinedSubtypesInFrenchSystemLocale() { final RunInLocale<Void> tests = new RunInLocale<Void>() { @@ -276,13 +348,21 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "Allemand (Suisse)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); + assertEquals("hi", "Hindi", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI)); + assertEquals("sr", "Serbe", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR)); assertEquals("zz", "Alphabet latin (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); - // This is a preliminary subtype and may not exist. + // These are preliminary subtypes and may not exist. if (HI_LATN != null) { assertEquals("hi_ZZ", "Hindi/Anglais", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "Serbe (latin)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN)); + } return null; } }; @@ -307,12 +387,77 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); assertEquals("zz pc", "Alphabet latin (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); + // These are preliminary subtypes and may not exist. + if (HI_LATN_DVORAK != null) { + assertEquals("hi_ZZ", "Hindi/Anglais (Dvorak)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK)); + } + if (SR_LATN_QWERTY != null) { + assertEquals("sr_ZZ", "Serbe (QWERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY)); + } return null; } }; tests.runInLocale(mRes, Locale.FRENCH); } + // InputMethodSubtype's display name in system locale (hi). + // isAdditionalSubtype (T=true, F=false) + // locale layout | display name + // ------ ------- - ---------------------- + // hi hindi F हिन्दी + // hi_ZZ qwerty F हिंग्लिश + // hi_ZZ dvorak T हिंग्लिश (Dvorak) + + public void testHinglishSubtypesInHindiSystemLocale() { + final RunInLocale<Void> tests = new RunInLocale<Void>() { + @Override + protected Void job (final Resources res) { + assertEquals("hi", "हिन्दी", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI)); + // These are preliminary subtypes and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "हिंग्लिश", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); + assertEquals("hi_ZZ", "हिंग्लिश (Dvorak)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK)); + } + return null; + } + }; + tests.runInLocale(mRes, new Locale("hi")); + } + + // InputMethodSubtype's display name in system locale (sr). + // isAdditionalSubtype (T=true, F=false) + // locale layout | display name + // ------ -------------- - ---------------------- + // sr south_slavic F Српски + // sr_ZZ serbian_qwertz F српски (латиница) + // sr_ZZ qwerty T српски (QWERTY) + + public void testSerbianLatinSubtypesInSerbianSystemLocale() { + final RunInLocale<Void> tests = new RunInLocale<Void>() { + @Override + protected Void job (final Resources res) { + assertEquals("sr", "Српски", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR)); + // These are preliminary subtypes and may not exist. + if (SR_LATN != null) { + // TODO: Uncommented because of the current translation of these strings + // in Seriban are described in Latin script. +// assertEquals("sr_ZZ", "српски (латиница)", +// SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN)); +// assertEquals("sr_ZZ", "српски (QWERTY)", +// SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY)); + } + return null; + } + }; + tests.runInLocale(mRes, new Locale("sr")); + } + public void testIsRtlLanguage() { // Known Right-to-Left language subtypes. final InputMethodSubtype ARABIC = mRichImm diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index 09af9a020..90be411ec 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -60,8 +60,7 @@ LATINIME_SRC_FILES_FOR_DICTTOOL := \ latin/utils/FileUtils.java \ latin/utils/JniUtils.java \ latin/utils/LocaleUtils.java \ - latin/utils/ResizableIntArray.java \ - latin/utils/StringUtils.java + latin/utils/ResizableIntArray.java LATINIME_OVERRIDABLE_SRC_FILES_FOR_DICTTOOL := \ latin/define/DebugFlags.java |