diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java index 4ea7fb888..ee9125a07 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java @@ -19,6 +19,7 @@ package com.android.inputmethod.compat; import android.os.Build; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; import java.lang.reflect.Constructor; @@ -64,7 +65,12 @@ public final class InputMethodSubtypeCompatUtils { } public static boolean isAsciiCapable(final InputMethodSubtype subtype) { - return (Boolean)CompatUtils.invoke(subtype, false, METHOD_isAsciiCapable) + return isAsciiCapableWithAPI(subtype) || subtype.containsExtraValueKey(Constants.Subtype.ExtraValue.ASCII_CAPABLE); } + + @UsedForTesting + public static boolean isAsciiCapableWithAPI(final InputMethodSubtype subtype) { + return (Boolean)CompatUtils.invoke(subtype, false, METHOD_isAsciiCapable); + } } diff --git a/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java index 31fa86774..ad411f9ee 100644 --- a/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java @@ -150,8 +150,9 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { // TODO: Should filter out already existing combinations of locale and layout. for (final String layout : SubtypeLocaleUtils.getPredefinedKeyboardLayoutSet()) { // This is a dummy subtype with NO_LANGUAGE, only for display. - final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAdditionalSubtype( - SubtypeLocaleUtils.NO_LANGUAGE, layout, null); + final InputMethodSubtype subtype = + AdditionalSubtypeUtils.createDummyAdditionalSubtype( + SubtypeLocaleUtils.NO_LANGUAGE, layout); add(new KeyboardLayoutSetItem(subtype)); } } @@ -286,8 +287,9 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem(); final KeyboardLayoutSetItem layout = (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem(); - final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAdditionalSubtype( - locale.first, layout.first, Constants.Subtype.ExtraValue.ASCII_CAPABLE); + final InputMethodSubtype subtype = + AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + locale.first, layout.first); setSubtype(subtype); notifyChanged(); if (isEditing) { diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index b57eab31b..90c8f618f 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -374,8 +374,8 @@ public final class AndroidSpellCheckerService extends SpellCheckerService public DictAndKeyboard createDictAndKeyboard(final Locale locale) { final int script = ScriptUtils.getScriptFromSpellCheckerLocale(locale); final String keyboardLayoutName = getKeyboardLayoutNameForScript(script); - final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAdditionalSubtype( - locale.toString(), keyboardLayoutName, null); + final InputMethodSubtype subtype = AdditionalSubtypeUtils.createDummyAdditionalSubtype( + locale.toString(), keyboardLayoutName); final KeyboardLayoutSet keyboardLayoutSet = createKeyboardSetForSpellChecker(subtype); final DictionaryCollection dictionaryCollection = diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java index 3ca7c7e1c..db7f2a56c 100644 --- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin.utils; import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.EMOJI_CAPABLE; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; @@ -56,25 +57,33 @@ public final class AdditionalSubtypeUtils { private static final int LENGTH_WITH_EXTRA_VALUE = (INDEX_OF_EXTRA_VALUE + 1); private static final String PREF_SUBTYPE_SEPARATOR = ";"; - public static InputMethodSubtype createAdditionalSubtype(final String localeString, - final String keyboardLayoutSetName, final String extraValue) { - final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; - final String layoutDisplayNameExtraValue; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN - && SubtypeLocaleUtils.isExceptionalLocale(localeString)) { - final String layoutDisplayName = SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName( - keyboardLayoutSetName); - layoutDisplayNameExtraValue = StringUtils.appendToCommaSplittableTextIfNotExists( - UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME + "=" + layoutDisplayName, extraValue); - } else { - layoutDisplayNameExtraValue = extraValue; - } - final String additionalSubtypeExtraValue = - StringUtils.appendToCommaSplittableTextIfNotExists( - IS_ADDITIONAL_SUBTYPE, layoutDisplayNameExtraValue); + private static InputMethodSubtype createAdditionalSubtypeInternal( + final String localeString, final String keyboardLayoutSetName, + final boolean isAsciiCapable, final boolean isEmojiCapable) { final int nameId = SubtypeLocaleUtils.getSubtypeNameId(localeString, keyboardLayoutSetName); - return buildInputMethodSubtype( - nameId, localeString, layoutExtraValue, additionalSubtypeExtraValue); + final String platformVersionDependentExtraValues = getPlatformVersionDependentExtraValue( + localeString, keyboardLayoutSetName, isAsciiCapable, isEmojiCapable); + final int platformVersionIndependentSubtypeId = + getPlatformVersionIndependentSubtypeId(localeString, keyboardLayoutSetName); + // NOTE: In KitKat and later, InputMethodSubtypeBuilder#setIsAsciiCapable is also available. + // TODO: Use InputMethodSubtypeBuilder#setIsAsciiCapable when appropriate. + return InputMethodSubtypeCompatUtils.newInputMethodSubtype(nameId, + R.drawable.ic_ime_switcher_dark, localeString, KEYBOARD_MODE, + platformVersionDependentExtraValues, + false /* isAuxiliary */, false /* overrideImplicitlyEnabledSubtype */, + platformVersionIndependentSubtypeId); + } + + public static InputMethodSubtype createDummyAdditionalSubtype( + final String localeString, final String keyboardLayoutSetName) { + return createAdditionalSubtypeInternal(localeString, keyboardLayoutSetName, + false /* isAsciiCapable */, false /* isEmojiCapable */); + } + + public static InputMethodSubtype createAsciiEmojiCapableAdditionalSubtype( + final String localeString, final String keyboardLayoutSetName) { + return createAdditionalSubtypeInternal(localeString, keyboardLayoutSetName, + true /* isAsciiCapable */, true /* isEmojiCapable */); } public static String getPrefSubtype(final InputMethodSubtype subtype) { @@ -106,10 +115,10 @@ public final class AdditionalSubtypeUtils { } final String localeString = elems[INDEX_OF_LOCALE]; final String keyboardLayoutSetName = elems[INDEX_OF_KEYBOARD_LAYOUT]; - final String extraValue = (elems.length == LENGTH_WITH_EXTRA_VALUE) - ? elems[INDEX_OF_EXTRA_VALUE] : null; - final InputMethodSubtype subtype = createAdditionalSubtype( - localeString, keyboardLayoutSetName, extraValue); + // Here we assume that all the additional subtypes have AsciiCapable and EmojiCapable. + // This is actually what the setting dialog for additional subtype is doing. + final InputMethodSubtype subtype = createAsciiEmojiCapableAdditionalSubtype( + localeString, keyboardLayoutSetName); if (subtype.getNameResId() == SubtypeLocaleUtils.UNKNOWN_KEYBOARD_LAYOUT) { // Skip unknown keyboard layout subtype. This may happen when predefined keyboard // layout has been removed. @@ -148,35 +157,80 @@ public final class AdditionalSubtypeUtils { return sb.toString(); } - private static InputMethodSubtype buildInputMethodSubtype(final int nameId, - final String localeString, final String layoutExtraValue, - final String additionalSubtypeExtraValue) { - // To preserve additional subtype settings and user's selection across OS updates, subtype - // id shouldn't be changed. New attributes, such as emojiCapable, are carefully excluded - // from the calculation of subtype id. - final String compatibleExtraValue = StringUtils.joinCommaSplittableText( - layoutExtraValue, additionalSubtypeExtraValue); - final int compatibleSubtypeId = getInputMethodSubtypeId(localeString, compatibleExtraValue); - final String extraValue; - // Color Emoji is supported from KitKat. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - extraValue = StringUtils.appendToCommaSplittableTextIfNotExists( - EMOJI_CAPABLE, compatibleExtraValue); - } else { - extraValue = compatibleExtraValue; + /** + * Returns the extra value that is optimized for the running OS. + *
+ * Historically the extra value has been used as the last resort to annotate various kinds of + * attributes. Some of these attributes are valid only on some platform versions. Thus we cannot + * assume that the extra values stored in a persistent storage are always valid. We need to + * regenerate the extra value on the fly instead. + *
+ * @param localeString the locale string (e.g., "en_US"). + * @param keyboardLayoutSetName the keyboard layout set name (e.g., "dvorak"). + * @param isAsciiCapable true when ASCII characters are supported with this layout. + * @param isEmojiCapable true when Unicode Emoji characters are supported with this layout. + * @return extra value that is optimized for the running OS. + * @see #getPlatformVersionIndependentSubtypeId(String, String) + */ + private static String getPlatformVersionDependentExtraValue(final String localeString, + final String keyboardLayoutSetName, final boolean isAsciiCapable, + final boolean isEmojiCapable) { + final ArrayList
+ * From the compatibility point of view, it is important to keep subtype id predictable and
+ * stable between different OSes. For this purpose, the calculation code in this method is
+ * carefully chosen and then fixed. Treat the following code as no more or less than a
+ * hash function. Each component to be hashed can be different from the corresponding value
+ * that is used to instantiate {@link InputMethodSubtype} actually.
+ * For example, you don't need to update compatibilityExtraValueItems
in this
+ * method even when we need to add some new extra values for the actual instance of
+ * {@link InputMethodSubtype}.
+ *
+ * final boolean isAuxiliary = false;
+ * final boolean overrideImplicitlyEnabledSubtype = false;
+ * final int SUBTYPE_ID_EN_US_DVORAK = Arrays.hashCode(new Object[] {
+ * "en_US",
+ * "keyboard",
+ * "KeyboardLayoutSet=dvorak"
+ * + ",AsciiCapable"
+ * + ",UntranslatableReplacementStringInSubtypeName=Dvorak"
+ * + ",EmojiCapable"
+ * + ",isAdditionalSubtype",
+ * isAuxiliary,
+ * overrideImplicitlyEnabledSubtype });
+ *
+ */
+ private static int SUBTYPE_ID_EN_US_DVORAK = 0xb3c0cc56;
+ private static String EXTRA_VALUE_EN_US_DVORAK_ICS =
+ "KeyboardLayoutSet=dvorak" +
+ ",AsciiCapable" +
+ ",isAdditionalSubtype";
+ private static String EXTRA_VALUE_EN_US_DVORAK_JELLY_BEAN =
+ "KeyboardLayoutSet=dvorak" +
+ ",AsciiCapable" +
+ ",UntranslatableReplacementStringInSubtypeName=Dvorak" +
+ ",isAdditionalSubtype";
+ private static String EXTRA_VALUE_EN_US_DVORAK_KITKAT =
+ "KeyboardLayoutSet=dvorak" +
+ ",AsciiCapable" +
+ ",UntranslatableReplacementStringInSubtypeName=Dvorak" +
+ ",EmojiCapable" +
+ ",isAdditionalSubtype";
+
+ /**
+ * Predictable subtype ID for azerty layout. This is actually a hash code calculated as follows.
+ *
+ * final boolean isAuxiliary = false;
+ * final boolean overrideImplicitlyEnabledSubtype = false;
+ * final int SUBTYPE_ID_ZZ_AZERTY = Arrays.hashCode(new Object[] {
+ * "zz",
+ * "keyboard",
+ * "KeyboardLayoutSet=azerty"
+ * + ",AsciiCapable"
+ * + ",EmojiCapable"
+ * + ",isAdditionalSubtype",
+ * isAuxiliary,
+ * overrideImplicitlyEnabledSubtype });
+ *
+ */
+ private static int SUBTYPE_ID_ZZ_AZERTY = 0x5b6be697;
+ private static String EXTRA_VALUE_ZZ_AZERTY_ICS =
+ "KeyboardLayoutSet=azerty" +
+ ",AsciiCapable" +
+ ",isAdditionalSubtype";
+ private static String EXTRA_VALUE_ZZ_AZERTY_KITKAT =
+ "KeyboardLayoutSet=azerty" +
+ ",AsciiCapable" +
+ ",EmojiCapable" +
+ ",isAdditionalSubtype";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final Context context = getContext();
+ SubtypeLocaleUtils.init(context);
+ }
+
+ private static void assertEnUsDvorak(InputMethodSubtype subtype) {
+ assertEquals("en_US", subtype.getLocale());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertEquals(EXTRA_VALUE_EN_US_DVORAK_KITKAT, subtype.getExtraValue());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ assertEquals(EXTRA_VALUE_EN_US_DVORAK_JELLY_BEAN, subtype.getExtraValue());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ assertEquals(EXTRA_VALUE_EN_US_DVORAK_ICS, subtype.getExtraValue());
+ }
+ assertTrue(subtype.containsExtraValueKey(ASCII_CAPABLE));
+ assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapable(subtype));
+ // TODO: Enable following test
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype));
+ // }
+ assertTrue(subtype.containsExtraValueKey(EMOJI_CAPABLE));
+ assertTrue(subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE));
+ assertEquals("dvorak", subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET));
+ assertEquals("Dvorak", subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME));
+ assertEquals(KEYBOARD_MODE, subtype.getMode());
+ assertEquals(SUBTYPE_ID_EN_US_DVORAK, subtype.hashCode());
+ }
+
+ private static void assertAzerty(InputMethodSubtype subtype) {
+ assertEquals("zz", subtype.getLocale());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertEquals(EXTRA_VALUE_ZZ_AZERTY_KITKAT, subtype.getExtraValue());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ assertEquals(EXTRA_VALUE_ZZ_AZERTY_ICS, subtype.getExtraValue());
+ }
+ assertTrue(subtype.containsExtraValueKey(ASCII_CAPABLE));
+ assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapable(subtype));
+ // TODO: Enable following test
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype));
+ // }
+ assertTrue(subtype.containsExtraValueKey(EMOJI_CAPABLE));
+ assertTrue(subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE));
+ assertEquals("azerty", subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET));
+ assertFalse(subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME));
+ assertEquals(KEYBOARD_MODE, subtype.getMode());
+ assertEquals(SUBTYPE_ID_ZZ_AZERTY, subtype.hashCode());
+ }
+
+ public void testRestorable() {
+ final InputMethodSubtype EN_UK_DVORAK =
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.US.toString(), "dvorak");
+ final InputMethodSubtype ZZ_AZERTY =
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
+ assertEnUsDvorak(EN_UK_DVORAK);
+ assertAzerty(ZZ_AZERTY);
+
+ // Make sure the subtype can be stored and restored in a deterministic manner.
+ final InputMethodSubtype[] subtypes = { EN_UK_DVORAK, ZZ_AZERTY };
+ final String prefSubtype = AdditionalSubtypeUtils.createPrefSubtypes(subtypes);
+ final InputMethodSubtype[] restoredSubtypes =
+ AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype);
+ assertEquals(2, restoredSubtypes.length);
+ final InputMethodSubtype restored_EN_UK_DVORAK = restoredSubtypes[0];
+ final InputMethodSubtype restored_ZZ_AZERTY = restoredSubtypes[1];
+
+ assertEnUsDvorak(restored_EN_UK_DVORAK);
+ assertAzerty(restored_ZZ_AZERTY);
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java
index 4156de78b..fdde34251 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java
@@ -87,20 +87,20 @@ public class SpacebarLanguagetUtilsTests extends AndroidTestCase {
"de_CH", "swiss");
ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
- DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.GERMAN.toString(), "qwerty", null);
- FR_QWERTZ = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.FRENCH.toString(), "qwertz", null);
- EN_US_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.US.toString(), "azerty", null);
- EN_UK_DVORAK = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.UK.toString(), "dvorak", null);
- ES_US_COLEMAK = AdditionalSubtypeUtils.createAdditionalSubtype(
- "es_US", "colemak", null);
- ZZ_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
- SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null);
- ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype(
- SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null);
+ DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.GERMAN.toString(), "qwerty");
+ FR_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.FRENCH.toString(), "qwertz");
+ EN_US_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.US.toString(), "azerty");
+ EN_UK_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.UK.toString(), "dvorak");
+ ES_US_COLEMAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ "es_US", "colemak");
+ ZZ_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
+ ZZ_PC = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty");
}
public void testAllFullDisplayNameForSpacebar() {
diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
index 8e409ab99..ce3df7dd6 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -87,20 +87,20 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
"de_CH", "swiss");
ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
- DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.GERMAN.toString(), "qwerty", null);
- FR_QWERTZ = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.FRENCH.toString(), "qwertz", null);
- EN_US_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.US.toString(), "azerty", null);
- EN_UK_DVORAK = AdditionalSubtypeUtils.createAdditionalSubtype(
- Locale.UK.toString(), "dvorak", null);
- ES_US_COLEMAK = AdditionalSubtypeUtils.createAdditionalSubtype(
- "es_US", "colemak", null);
- ZZ_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
- SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null);
- ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype(
- SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null);
+ DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.GERMAN.toString(), "qwerty");
+ FR_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.FRENCH.toString(), "qwertz");
+ EN_US_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.US.toString(), "azerty");
+ EN_UK_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.UK.toString(), "dvorak");
+ ES_US_COLEMAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ "es_US", "colemak");
+ ZZ_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
+ ZZ_PC = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty");
}
public void testAllFullDisplayName() {