diff options
22 files changed, 247 insertions, 126 deletions
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index b3f30c638..86f2abe72 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -403,11 +403,6 @@ <attr name="parentStyle" format="string" /> </declare-styleable> - <declare-styleable name="KeyboardSet"> - <!-- Disable shortcut key. Shortcut key is enabled by default. --> - <attr name="disableShortcutKey" format="boolean" /> - </declare-styleable> - <declare-styleable name="KeyboardSet_Element"> <!-- This should be aligned with KeyboardId.ELEMENT_* --> <attr name="elementName" format="enum"> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 68a8cabce..9c8bd3cd4 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -156,22 +156,20 @@ <string-array name="subtype_locale_exception_keys"> <item>en_US</item> <item>en_GB</item> - <item>de_QY</item> - <item>zz_QY</item> + <item>*_QY</item> + <item>QY</item> </string-array> <string-array name="subtype_locale_exception_values"> <item>English (US)</item> <item>English (UK)</item> <item>@string/subtype_generic_qwerty</item> - <item>@string/subtype_qwerty</item> + <item>QWERTY</item> </string-array> <!-- Generic subtype label --> <string name="subtype_generic">%s</string> <!-- Description for generic QWERTY keyboard subtype --> <string name="subtype_generic_qwerty">%s (QWERTY)</string> - <!-- Description for language agnostic QWERTY keyboard subtype --> - <string name="subtype_qwerty">QWERTY</string> <!-- dictionary pack package name /settings activity (for shared prefs and settings) --> <string name="dictionary_pack_package_name">com.google.android.inputmethod.latin.dictionarypack</string> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 4f038e1a5..a22c68cb8 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -252,6 +252,8 @@ <string name="subtype_en_GB">English (UK)</string> <!-- Description for English (United States) keyboard subtype [CHAR LIMIT=22] --> <string name="subtype_en_US">English (US)</string> + <!-- Description for language agnostic QWERTY keyboard subtype [CHAR LIMIT=22] --> + <string name="subtype_no_language_qwerty">No language (QWERTY)</string> <!-- Title of an option for usability study mode --> <string name="prefs_usability_study_mode">Usability study mode</string> diff --git a/java/res/xml-sw600dp/rowkeys_thai2.xml b/java/res/xml-sw600dp/rowkeys_thai2.xml index 0edae1c73..86a219854 100644 --- a/java/res/xml-sw600dp/rowkeys_thai2.xml +++ b/java/res/xml-sw600dp/rowkeys_thai2.xml @@ -39,10 +39,10 @@ <!-- U+0E18: "ธ" THAI CHARACTER THO THONG --> <Key latin:keyLabel="ธ" /> - <!-- U+0E4D: "กํ" THAI CHARACTER THANTHAKHAT --> + <!-- U+0E4D: " ํ" THAI CHARACTER THANTHAKHAT --> <Key latin:keyLabel="ํ" /> - <!-- U+0E4A: "ก๊" THAI CHARACTER MAI TRI --> + <!-- U+0E4A: " ๊" THAI CHARACTER MAI TRI --> <Key latin:keyLabel="๊" /> <!-- U+0E13: "ณ" THAI CHARACTER NO NEN --> @@ -79,10 +79,10 @@ <!-- U+0E30: "ะ" THAI CHARACTER SARA A --> <Key latin:keyLabel="ะ" /> - <!-- U+0E31: "กั" THAI CHARACTER MAI HAN-AKAT --> + <!-- U+0E31: " ั" THAI CHARACTER MAI HAN-AKAT --> <Key latin:keyLabel="ั" /> - <!-- U+0E35: "กี" HAI CHARACTER SARA II --> + <!-- U+0E35: " ี" HAI CHARACTER SARA II --> <Key latin:keyLabel="ี" /> <!-- U+0E23: "ร" THAI CHARACTER RO RUA --> diff --git a/java/res/xml-zz-rQY/keyboard_set.xml b/java/res/xml-zz-rQY/keyboard_set.xml index 6fa97017c..e9eddbf05 100644 --- a/java/res/xml-zz-rQY/keyboard_set.xml +++ b/java/res/xml-zz-rQY/keyboard_set.xml @@ -19,8 +19,7 @@ --> <KeyboardSet - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:disableShortcutKey="true" > + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"> <Element latin:elementName="alphabet" latin:elementKeyboard="@xml/kbd_qwerty" diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 7a21a856b..e43fb32a4 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -312,7 +312,7 @@ android:imeSubtypeExtraValue="AsciiCapable" /> <subtype android:icon="@drawable/ic_subtype_keyboard" - android:label="@string/subtype_qwerty" + android:label="@string/subtype_no_language_qwerty" android:imeSubtypeLocale="zz_QY" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable" diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java index d1af7a527..08c246f8b 100644 --- a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java @@ -21,12 +21,16 @@ import android.view.inputmethod.EditorInfo; import java.lang.reflect.Field; public class EditorInfoCompatUtils { + // EditorInfo.IME_FLAG_FORCE_ASCII has been introduced since API#16 (JellyBean). private static final Field FIELD_IME_FLAG_FORCE_ASCII = CompatUtils.getField( EditorInfo.class, "IME_FLAG_FORCE_ASCII"); private static final Integer OBJ_IME_FLAG_FORCE_ASCII = (Integer) CompatUtils .getFieldValue(null, null, FIELD_IME_FLAG_FORCE_ASCII); - // EditorInfo.IME_FLAG_FORCE_ASCII has been introduced since API#16 (JellyBean). + private EditorInfoCompatUtils() { + // This utility class is not publicly instantiable. + } + public static boolean hasFlagForceAscii(int imeOptions) { if (OBJ_IME_FLAG_FORCE_ASCII == null) return false; diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 7be95a095..ffed8202d 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -40,6 +40,10 @@ public class InputMethodManagerCompatWrapper { private InputMethodManager mImm; + private InputMethodManagerCompatWrapper() { + // This wrapper class is not publicly instantiable. + } + public static InputMethodManagerCompatWrapper getInstance() { if (sInstance.mImm == null) Log.w(TAG, "getInstance() is called before initialization"); diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index df55aee94..5c351e41f 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -77,6 +77,10 @@ public class SuggestionSpanUtils { } } + private SuggestionSpanUtils() { + // This utility class is not publicly instantiable. + } + public static CharSequence getTextWithAutoCorrectionIndicatorUnderline( Context context, CharSequence text) { if (TextUtils.isEmpty(text) || CONSTRUCTOR_SuggestionSpan == null diff --git a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java index 723ec2862..e5f9db27c 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java @@ -30,6 +30,7 @@ public class SuggestionsInfoCompatUtils { ? OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0; private SuggestionsInfoCompatUtils() { + // This utility class is not publicly instantiable. } /** diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index 263f17f74..efa4021b0 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -34,6 +34,7 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LocaleUtils.RunInLocale; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; @@ -99,7 +100,6 @@ public class KeyboardSet { int mMode; EditorInfo mEditorInfo; boolean mTouchPositionCorrectionEnabled; - boolean mDisableShortcutKey; boolean mVoiceKeyEnabled; boolean mVoiceKeyOnMain; boolean mNoSettingsKey; @@ -205,7 +205,8 @@ public class KeyboardSet { final Params params = mParams; final boolean isSymbols = (keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS || keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED); - final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !params.mDisableShortcutKey; + final boolean noLanguage = params.mLocale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE); + final boolean voiceKeyEnabled = params.mVoiceKeyEnabled && !noLanguage; final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain); return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey, @@ -247,7 +248,8 @@ public class KeyboardSet { final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( mParams.mEditorInfo.imeOptions) || deprecatedForceAscii; - mParams.mLocale = (forceAscii && !asciiCapable) ? Locale.US : inputLocale; + mParams.mLocale = (forceAscii && !asciiCapable) + ? SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY : inputLocale; return this; } @@ -301,11 +303,6 @@ public class KeyboardSet { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_KEYBOARD_SET.equals(tag)) { - final TypedArray a = mResources.obtainAttributes( - Xml.asAttributeSet(parser), R.styleable.KeyboardSet); - mParams.mDisableShortcutKey = a.getBoolean( - R.styleable.KeyboardSet_disableShortcutKey, false); - a.recycle(); parseKeyboardSetContent(parser); } else { throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index e2af97185..2689e6e13 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -47,7 +47,7 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResearchLogger; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; -import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SubtypeUtils; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; @@ -926,7 +926,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke paint.setTextAlign(Align.CENTER); paint.setTypeface(Typeface.DEFAULT); // Estimate appropriate language name text size to fit in maxTextWidth. - String language = StringUtils.getFullDisplayName(locale, true); + String language = SubtypeLocale.getFullDisplayName(locale); int textWidth = getTextWidth(paint, language, origTextSize); // Assuming text width and text size are proportional to each other. float textSize = origTextSize * Math.min(width / textWidth, 1.0f); @@ -938,7 +938,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final boolean useShortName; if (useMiddleName) { - language = StringUtils.getMiddleDisplayLanguage(locale); + language = SubtypeLocale.getMiddleDisplayName(locale); textWidth = getTextWidth(paint, language, origTextSize); textSize = origTextSize * Math.min(width / textWidth, 1.0f); useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) @@ -948,7 +948,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } if (useShortName) { - language = StringUtils.getShortDisplayLanguage(locale); + language = SubtypeLocale.getShortDisplayName(locale); textWidth = getTextWidth(paint, language, origTextSize); textSize = origTextSize * Math.min(width / textWidth, 1.0f); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index c43683f2d..92019c0ed 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -17,10 +17,14 @@ package com.android.inputmethod.latin; import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.content.res.Resources; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.LocaleUtils.RunInLocale; import java.util.Arrays; +import java.util.Locale; /** * Implements a static, compacted, binary dictionary of standard words. @@ -94,14 +98,23 @@ public class BinaryDictionary extends Dictionary { * @param flagArray the flags to limit the dictionary to, or null for default. */ public BinaryDictionary(final Context context, - final String filename, final long offset, final long length, Flag[] flagArray) { + final String filename, final long offset, final long length, final Flag[] flagArray, + Locale locale) { // Note: at the moment a binary dictionary is always of the "main" type. // Initializing this here will help transitioning out of the scheme where // the Suggest class knows everything about every single dictionary. mDicTypeId = Suggest.DIC_MAIN; // TODO: Stop relying on the state of SubtypeSwitcher, get it as a parameter - mFlags = Flag.initFlags(null == flagArray ? ALL_CONFIG_FLAGS : flagArray, context, - SubtypeSwitcher.getInstance()); + final RunInLocale<Void> job = new RunInLocale<Void>() { + @Override + protected Void job(Resources res) { + // TODO: remove this when all flags are moved to the native code + mFlags = Flag.initFlags(null == flagArray ? ALL_CONFIG_FLAGS : flagArray, context, + SubtypeSwitcher.getInstance()); + return null; + } + }; + job.runInLocale(context.getResources(), locale); loadDictionary(filename, offset, length); } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 7be374db5..7a59d80f1 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -59,7 +59,8 @@ public class DictionaryFactory { if (null != assetFileList) { for (final AssetFileAddress f : assetFileList) { final BinaryDictionary binaryDictionary = - new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, flagArray); + new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, flagArray, + locale); if (binaryDictionary.isValidDictionary()) { dictList.add(binaryDictionary); } @@ -119,7 +120,7 @@ public class DictionaryFactory { return null; } return new BinaryDictionary(context, - sourceDir, afd.getStartOffset(), afd.getLength(), null); + sourceDir, afd.getStartOffset(), afd.getLength(), null, locale); } catch (android.content.res.Resources.NotFoundException e) { Log.e(TAG, "Could not find the resource. resId=" + resId); return null; @@ -147,7 +148,7 @@ public class DictionaryFactory { long startOffset, long length, Flag[] flagArray) { if (dictionary.isFile()) { return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length, - flagArray); + flagArray, null); } else { Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); return null; diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 7b34cae63..7000e4633 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -22,7 +22,6 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Keyboard; import java.util.ArrayList; -import java.util.Locale; public class StringUtils { private StringUtils() { @@ -150,41 +149,4 @@ public class StringUtils { i++; } } - - public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { - if (returnsNameInThisLocale) { - return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); - } else { - return toTitleCase(locale.getDisplayName(), locale); - } - } - - public static String getDisplayLanguage(Locale locale) { - return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); - } - - public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase((LocaleUtils.constructLocaleFromString( - locale.getLanguage()).getDisplayLanguage(locale)), locale); - } - - public static String getShortDisplayLanguage(Locale locale) { - return toTitleCase(locale.getLanguage(), locale); - } - - public static String toTitleCase(String s, Locale locale) { - if (s.length() <= 1) { - // TODO: is this really correct? Shouldn't this be s.toUpperCase()? - return s; - } - // TODO: fix the bugs below - // - This does not work for Greek, because it returns upper case instead of title case. - // - It does not work for Serbian, because it fails to account for the "lj" character, - // which should be "Lj" in title case and "LJ" in upper case. - // - It does not work for Dutch, because it fails to account for the "ij" digraph, which - // are two different characters but both should be capitalized as "IJ" as if they were - // a single letter. - // - It also does not work with unicode surrogate code points. - return s.toUpperCase(locale).charAt(0) + s.substring(1); - } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index 66c13bd2e..ba67f3358 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -22,6 +22,13 @@ import android.content.res.Resources; import java.util.Locale; public class SubtypeLocale { + // Special language code to represent "no language". + public static final String NO_LANGUAGE = "zz"; + // Special country code to represent "QWERTY". + /* package for test */ static final String QWERTY = "QY"; + + public static final Locale LOCALE_NO_LANGUAGE_QWERTY = new Locale(NO_LANGUAGE, QWERTY); + private static String[] sExceptionKeys; private static String[] sExceptionValues; @@ -35,18 +42,82 @@ public class SubtypeLocale { sExceptionValues = res.getStringArray(R.array.subtype_locale_exception_values); } - public static String getFullDisplayName(Locale locale) { - final String localeCode = locale.toString(); + private static String lookupExceptionalLocale(String key) { for (int index = 0; index < sExceptionKeys.length; index++) { - if (sExceptionKeys[index].equals(localeCode)) { - final String value = sExceptionValues[index]; - if (value.indexOf("%s") >= 0) { - final String languageName = locale.getDisplayLanguage(locale); - return String.format(value, languageName); - } - return value; + if (sExceptionKeys[index].equals(key)) { + return sExceptionValues[index]; } } - return locale.getDisplayName(locale); + return null; + } + + // Get Locale's full display name in its locale. + // For example: + // "fr_CH" is converted to "Français (Suisse)". + // "de_QY" is converted to "Deutsche (QWERTY)". (Any locale that has country code "QY") + // "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just + // ends up with the keyboard layout name.) + public static String getFullDisplayName(Locale locale) { + final String key; + if (locale.getLanguage().equals(NO_LANGUAGE)) { + key = locale.getCountry(); + } else if (locale.getCountry().equals(QWERTY)) { + key = "*_" + QWERTY; + } else { + key = locale.toString(); + } + final String value = lookupExceptionalLocale(key); + if (value == null) { + return toTitleCase(locale.getDisplayName(locale), locale); + } + if (value.indexOf("%s") >= 0) { + final String languageName = toTitleCase(locale.getDisplayLanguage(locale), locale); + return String.format(value, languageName); + } + return value; + } + + // Get Locale's middle display name in its locale. + // For example: + // "fr_CH" is converted to "Français". + // "de_QY" is converted to "Deutsche". (Any locale that has country code "QY") + // "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just + // ends up with the keyboard layout name.) + public static String getMiddleDisplayName(Locale locale) { + if (NO_LANGUAGE.equals(locale.getLanguage())) { + return lookupExceptionalLocale(locale.getCountry()); + } else { + return toTitleCase(locale.getDisplayLanguage(locale), locale); + } + } + + // Get Locale's short display name in its locale. + // For example: + // "fr_CH" is converted to "Fr". + // "de_QY" is converted to "De". (Any locale that has country code "QY") + // "zz_QY" is converter to "QY". (The language code "zz" means "No language", thus just ends + // up with the keyboard layout name.) + public static String getShortDisplayName(Locale locale) { + if (NO_LANGUAGE.equals(locale.getLanguage())) { + return locale.getCountry(); + } else { + return toTitleCase(locale.getLanguage(), locale); + } + } + + public static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? + return s; + } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. + return s.toUpperCase(locale).charAt(0) + s.substring(1); } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index e35364420..7541bd31b 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -375,6 +375,9 @@ public class SubtypeSwitcher { } public boolean needsToDisplayLanguage(Locale keyboardLocale) { + if (keyboardLocale.equals(SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY)) { + return true; + } if (!keyboardLocale.equals(mInputLocale)) { return false; } @@ -420,10 +423,6 @@ public class SubtypeSwitcher { return KEYBOARD_MODE.equals(getCurrentSubtypeMode()); } - public String getInputLanguageName() { - return StringUtils.getDisplayLanguage(getInputLocale()); - } - ///////////////////////////// // Other utility functions // ///////////////////////////// diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 0c0ce182f..91110d888 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -87,8 +87,9 @@ public class SuggestedWords { final CompletionInfo[] infos) { final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); for (CompletionInfo info : infos) { - if (null != info) result.add(new SuggestedWordInfo(info.getText(), - SuggestedWordInfo.MAX_SCORE)); + if (null != info && info.getText() != null) { + result.add(new SuggestedWordInfo(info.getText(), SuggestedWordInfo.MAX_SCORE)); + } } return result; } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 7b13e40c2..cd01bb146 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -37,6 +37,7 @@ import com.android.inputmethod.latin.Flag; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary; import com.android.inputmethod.latin.WhitelistDictionary; @@ -325,8 +326,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService } else if (CAPITALIZE_FIRST == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // Likewise - mSuggestions.set(i, StringUtils.toTitleCase(mSuggestions.get(i).toString(), - locale)); + mSuggestions.set(i, SubtypeLocale.toTitleCase( + mSuggestions.get(i).toString(), locale)); } } // This returns a String[], while toArray() returns an Object[] which cannot be cast diff --git a/tests/src/com/android/inputmethod/latin/InputLogicFrenchTests.java b/tests/src/com/android/inputmethod/latin/InputLogicFrenchTests.java index 5db120d82..60a7b05a9 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicFrenchTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicFrenchTests.java @@ -16,8 +16,6 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.keyboard.Keyboard; - public class InputLogicFrenchTests extends InputTestsBase { public void testAutoCorrectForFrench() { diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index 5f6b229dd..4dfe22800 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -95,7 +95,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); final boolean previousDebugSetting = prefs.getBoolean(PREF_DEBUG_MODE, false); final SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(PREF_DEBUG_MODE, true); + editor.putBoolean(PREF_DEBUG_MODE, mode); editor.commit(); return previousDebugSetting; } @@ -138,17 +138,20 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { final InputMethodManager imm = (InputMethodManager)mLatinIME.getSystemService( Context.INPUT_METHOD_SERVICE); final String packageName = mLatinIME.getPackageName(); - for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) { + // The IMEs and subtypes don't need to be enabled to run this test because IMF isn't + // involved here. + for (final InputMethodInfo imi : imm.getInputMethodList()) { if (imi.getPackageName().equals(packageName)) { - for (final InputMethodSubtype ims : - imm.getEnabledInputMethodSubtypeList(imi, true)) { + final int subtypeCount = imi.getSubtypeCount(); + for (int i = 0; i < subtypeCount; i++) { + final InputMethodSubtype ims = imi.getSubtypeAt(i); final String locale = ims.getLocale(); mSubtypeMap.put(locale, ims); } return; } } - fail("LatinIME is disabled"); + fail("LatinIME is not found"); } // We need to run the messages added to the handler from LatinIME. The only way to do @@ -176,7 +179,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { // The only way to get out of Looper#loop() is to call #quit() on it (or on its queue). // Once #quit() is called remaining messages are not processed, which is why we post // a message that calls it instead of calling it directly. - looper.loop(); + Looper.loop(); // Once #quit() has been called, the message queue has an "mQuiting" field that prevents // any subsequent post in this queue. However the queue itself is still fully functional! diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index 089fdc52c..6180ff5f9 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -23,11 +23,14 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import java.util.ArrayList; -import java.util.List; import java.util.Locale; public class SubtypeLocaleTests extends AndroidTestCase { - private List<InputMethodSubtype> mKeyboardSubtypes; + private static final Locale LOCALE_zz_QY = SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY; + private static final Locale LOCALE_de_QY = + new Locale(Locale.GERMAN.getLanguage(), SubtypeLocale.QWERTY); + + private ArrayList<InputMethodSubtype> mSubtypesList; @Override protected void setUp() throws Exception { @@ -42,46 +45,111 @@ public class SubtypeLocaleTests extends AndroidTestCase { Context.INPUT_METHOD_SERVICE); for (final InputMethodInfo imi : imm.getInputMethodList()) { if (imi.getPackageName().equals(packageName)) { - mKeyboardSubtypes = new ArrayList<InputMethodSubtype>(); + mSubtypesList = new ArrayList<InputMethodSubtype>(); final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - InputMethodSubtype subtype = imi.getSubtypeAt(i); - if (subtype.getMode().equals("keyboard")) { - mKeyboardSubtypes.add(subtype); - } + for (int i = 0; i < subtypeCount; i++) { + final InputMethodSubtype ims = imi.getSubtypeAt(i); + mSubtypesList.add(ims); } break; } } - assertNotNull("Can not find input method " + packageName, mKeyboardSubtypes); - assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0); + assertNotNull("Can not find input method " + packageName, mSubtypesList); + assertTrue("Can not find keyboard subtype", mSubtypesList.size() > 0); + } + + private static Locale getSubtypeLocale(InputMethodSubtype subtype) { + return LocaleUtils.constructLocaleFromString(subtype.getLocale()); + } + + private static Locale getKeyboardLocale(InputMethodSubtype subtype) { + final String subtypeLocaleString = subtype.containsExtraValueKey( + LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + : subtype.getLocale(); + return LocaleUtils.constructLocaleFromString(subtypeLocaleString); } - public void testSubtypeLocale() { + public void testFullDisplayName() { final StringBuilder messages = new StringBuilder(); int failedCount = 0; - for (final InputMethodSubtype subtype : mKeyboardSubtypes) { - final Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale()); - if (locale.getLanguage().equals("zz")) { + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { // This is special language name for language agnostic usage. continue; } - final String subtypeLocaleString = - subtype.containsExtraValueKey(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - : subtype.getLocale(); - final Locale subtypeLocale = LocaleUtils.constructLocaleFromString(subtypeLocaleString); - // The subtype name in its locale. For example 'English (US)' or 'Deutsch (QWERTY)'. - final String subtypeName = SubtypeLocale.getFullDisplayName(subtypeLocale); - // The locale language name in its locale. - final String languageName = locale.getDisplayLanguage(locale); - if (!subtypeName.contains(languageName)) { + final String keyboardName = SubtypeLocale.getFullDisplayName(locale); + final String languageName = SubtypeLocale.toTitleCase( + locale.getDisplayLanguage(locale), locale); + if (!keyboardName.contains(languageName)) { failedCount++; messages.append(String.format( - "subtype name is '%s' and should contain locale '%s' language name '%s'\n", - subtypeName, subtypeLocale, languageName)); + "locale %s: keyboard name '%s' should contain language name '%s'\n", + locale, keyboardName, languageName)); } } assertEquals(messages.toString(), 0, failedCount); } + + public void testFullDisplayNameNoLanguage() { + assertEquals("zz_QY", "QWERTY", SubtypeLocale.getFullDisplayName(LOCALE_zz_QY)); + + final String de_QY = SubtypeLocale.getFullDisplayName(LOCALE_de_QY); + assertTrue("de_QY", de_QY.contains("(QWERTY")); + assertTrue("de_QY", de_QY.contains(Locale.GERMAN.getDisplayLanguage(Locale.GERMAN))); + } + + public void testMiddleDisplayName() { + final StringBuilder messages = new StringBuilder(); + int failedCount = 0; + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { + // This is special language name for language agnostic usage. + continue; + } + final String keyboardName = SubtypeLocale.getMiddleDisplayName(locale); + final String languageName = SubtypeLocale.toTitleCase( + locale.getDisplayLanguage(locale), locale); + if (!keyboardName.equals(languageName)) { + failedCount++; + messages.append(String.format( + "locale %s: keyboard name '%s' should be equals to language name '%s'\n", + locale, keyboardName, languageName)); + } + } + assertEquals(messages.toString(), 0, failedCount); + } + + public void testMiddleDisplayNameNoLanguage() { + assertEquals("zz_QY", "QWERTY", SubtypeLocale.getMiddleDisplayName(LOCALE_zz_QY)); + assertEquals("de_QY", "Deutsch", SubtypeLocale.getMiddleDisplayName(LOCALE_de_QY)); + } + + public void testShortDisplayName() { + final StringBuilder messages = new StringBuilder(); + int failedCount = 0; + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getCountry().equals(SubtypeLocale.QWERTY)) { + // This is special country code for QWERTY keyboard. + continue; + } + final String keyboardName = SubtypeLocale.getShortDisplayName(locale); + final String languageCode = SubtypeLocale.toTitleCase(locale.getLanguage(), locale); + if (!keyboardName.equals(languageCode)) { + failedCount++; + messages.append(String.format( + "locale %s: keyboard name '%s' should be equals to language code '%s'\n", + locale, keyboardName, languageCode)); + } + } + assertEquals(messages.toString(), 0, failedCount); + } + + public void testShortDisplayNameNoLanguage() { + assertEquals("zz_QY", "QY", SubtypeLocale.getShortDisplayName(LOCALE_zz_QY)); + assertEquals("de_QY", "De", SubtypeLocale.getShortDisplayName(LOCALE_de_QY)); + } } |