1e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka/*
2e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
3e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka *
4e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * you may not use this file except in compliance with the License.
6e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * You may obtain a copy of the License at
7e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka *
8e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka *
10e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * See the License for the specific language governing permissions and
14e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka * limitations under the License.
15e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka */
16e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka
17e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaokapackage com.android.inputmethod.latin;
18e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka
191cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
208e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME;
211cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka
22e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaokaimport android.content.Context;
23e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaokaimport android.content.res.Resources;
248e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaokaimport android.os.Build;
25ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaokaimport android.util.Log;
268abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype;
278abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka
28757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaokaimport com.android.inputmethod.latin.LocaleUtils.RunInLocale;
29757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka
30f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaokaimport java.util.HashMap;
31e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaokaimport java.util.Locale;
32e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka
33a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class SubtypeLocale {
34ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka    static final String TAG = SubtypeLocale.class.getSimpleName();
3538026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    // This class must be located in the same package as LatinIME.java.
3638026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    private static final String RESOURCE_PACKAGE_NAME =
3738026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka            DictionaryFactory.class.getPackage().getName();
38c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka
393bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaoka    // Special language code to represent "no language".
40a58ebc73ae3eb2783713c471d8abb348c7dfc8daTadashi G. Takaoka    public static final String NO_LANGUAGE = "zz";
4138026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    public static final String QWERTY = "qwerty";
4296e404310deca42a6696abdcb3111d355815b547Tadashi G. Takaoka    public static final int UNKNOWN_KEYBOARD_LAYOUT = R.string.subtype_generic;
4396e404310deca42a6696abdcb3111d355815b547Tadashi G. Takaoka
44d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka    private static boolean sInitialized = false;
4538026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    private static String[] sPredefinedKeyboardLayoutSet;
4638026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    // Keyboard layout to its display name map.
478e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    private static final HashMap<String, String> sKeyboardLayoutToDisplayNameMap =
485f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka            CollectionUtils.newHashMap();
4938026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    // Keyboard layout to subtype name resource id map.
5038026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap =
515f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka            CollectionUtils.newHashMap();
528e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    // Exceptional locale to subtype name resource id map.
538e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    private static final HashMap<String, Integer> sExceptionalLocaleToWithLayoutNameIdsMap =
545f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka            CollectionUtils.newHashMap();
5527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    private static final String SUBTYPE_NAME_RESOURCE_GENERIC_PREFIX =
5627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            "string/subtype_generic_";
578e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    private static final String SUBTYPE_NAME_RESOURCE_WITH_LAYOUT_PREFIX =
588e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            "string/subtype_with_layout_";
5927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    private static final String SUBTYPE_NAME_RESOURCE_NO_LANGUAGE_PREFIX =
6027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            "string/subtype_no_language_";
61f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka    // Exceptional locales to display name map.
62f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka    private static final HashMap<String, String> sExceptionalDisplayNamesMap =
635f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka            CollectionUtils.newHashMap();
647f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka    // Keyboard layout set name for the subtypes that don't have a keyboardLayoutSet extra value.
657f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka    // This is for compatibility to keep the same subtype ids as pre-JellyBean.
667f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka    private static final HashMap<String,String> sLocaleAndExtraValueToKeyboardLayoutSetMap =
675f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka            CollectionUtils.newHashMap();
688abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka
69e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka    private SubtypeLocale() {
70e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka        // Intentional empty constructor for utility class.
71e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka    }
72e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka
73d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka    // Note that this initialization method can be called multiple times.
74d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka    public static synchronized void init(Context context) {
75d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka        if (sInitialized) return;
76d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka
77e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka        final Resources res = context.getResources();
7838026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka
7938026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        final String[] predefinedLayoutSet = res.getStringArray(R.array.predefined_layouts);
8038026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        sPredefinedKeyboardLayoutSet = predefinedLayoutSet;
8138026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        final String[] layoutDisplayNames = res.getStringArray(
8238026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka                R.array.predefined_layout_display_names);
8338026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        for (int i = 0; i < predefinedLayoutSet.length; i++) {
8438026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka            final String layoutName = predefinedLayoutSet[i];
858e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            sKeyboardLayoutToDisplayNameMap.put(layoutName, layoutDisplayNames[i]);
8627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            final String resourceName = SUBTYPE_NAME_RESOURCE_GENERIC_PREFIX + layoutName;
8738026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka            final int resId = res.getIdentifier(resourceName, null, RESOURCE_PACKAGE_NAME);
8838026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka            sKeyboardLayoutToNameIdsMap.put(layoutName, resId);
8927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            // Register subtype name resource id of "No language" with key "zz_<layout>"
9027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            final String noLanguageResName = SUBTYPE_NAME_RESOURCE_NO_LANGUAGE_PREFIX + layoutName;
9127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            final int noLanguageResId = res.getIdentifier(
9227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka                    noLanguageResName, null, RESOURCE_PACKAGE_NAME);
9327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            final String key = getNoLanguageLayoutKey(layoutName);
9427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka            sKeyboardLayoutToNameIdsMap.put(key, noLanguageResId);
9538026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        }
9638026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka
9738026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        final String[] exceptionalLocales = res.getStringArray(
9838026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka                R.array.subtype_locale_exception_keys);
9938026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        final String[] exceptionalDisplayNames = res.getStringArray(
10038026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka                R.array.subtype_locale_exception_values);
10138026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        for (int i = 0; i < exceptionalLocales.length; i++) {
1028e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            final String localeString = exceptionalLocales[i];
1038e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            sExceptionalDisplayNamesMap.put(localeString, exceptionalDisplayNames[i]);
1048e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            final String resourceName = SUBTYPE_NAME_RESOURCE_WITH_LAYOUT_PREFIX + localeString;
1058e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            final int resId = res.getIdentifier(resourceName, null, RESOURCE_PACKAGE_NAME);
1068e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            sExceptionalLocaleToWithLayoutNameIdsMap.put(localeString, resId);
107e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka        }
1087f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka
1097f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka        final String[] keyboardLayoutSetMap = res.getStringArray(
1107f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka                R.array.locale_and_extra_value_to_keyboard_layout_set_map);
1117f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka        for (int i = 0; i < keyboardLayoutSetMap.length; i += 2) {
1127f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            final String key = keyboardLayoutSetMap[i];
1137f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            final String keyboardLayoutSet = keyboardLayoutSetMap[i + 1];
1147f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            sLocaleAndExtraValueToKeyboardLayoutSetMap.put(key, keyboardLayoutSet);
1157f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka        }
116d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka
117d6ac0443f0250281872fd889c81d8cbd71e72736Tadashi G. Takaoka        sInitialized = true;
1183bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaoka    }
1193bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaoka
12038026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    public static String[] getPredefinedKeyboardLayoutSet() {
12138026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka        return sPredefinedKeyboardLayoutSet;
12238026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    }
12338026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka
1248e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    public static boolean isExceptionalLocale(String localeString) {
1258e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka        return sExceptionalLocaleToWithLayoutNameIdsMap.containsKey(localeString);
1268e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    }
1278e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka
12827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    private static final String getNoLanguageLayoutKey(String keyboardLayoutName) {
12927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka        return NO_LANGUAGE + "_" + keyboardLayoutName;
13038026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka    }
13138026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka
13227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    public static int getSubtypeNameId(String localeString, String keyboardLayoutName) {
133165725aba8a179440af9c93869b35f206b2e133fTadashi G. Takaoka        if (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 && isExceptionalLocale(localeString)) {
1348e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka            return sExceptionalLocaleToWithLayoutNameIdsMap.get(localeString);
1358e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka        }
13627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka        final String key = localeString.equals(NO_LANGUAGE)
13727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka                ? getNoLanguageLayoutKey(keyboardLayoutName)
13827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka                : keyboardLayoutName;
13927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka        final Integer nameId = sKeyboardLayoutToNameIdsMap.get(key);
14027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka        return nameId == null ? UNKNOWN_KEYBOARD_LAYOUT : nameId;
14127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    }
142c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka
14327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    public static String getSubtypeLocaleDisplayName(String localeString) {
14427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka        final String exceptionalValue = sExceptionalDisplayNamesMap.get(localeString);
145c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka        if (exceptionalValue != null) {
146c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka            return exceptionalValue;
147c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka        }
14827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka        final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
149f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka        return StringUtils.toTitleCase(locale.getDisplayName(locale), locale);
1503bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaoka    }
1513bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaoka
15227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    // InputMethodSubtype's display name in its locale.
15327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //        isAdditionalSubtype (T=true, F=false)
15427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    // locale layout |  display name
15527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    // ------ ------ - ----------------------
15627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  en_US qwerty F  English (US)            exception
15727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  en_GB qwerty F  English (UK)            exception
15827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  fr    azerty F  Français
15927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  fr_CA qwerty F  Français (Canada)
16027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  de    qwertz F  Deutsch
161757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka    //  zz    qwerty F  No language (QWERTY)    in system locale
16227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  fr    qwertz T  Français (QWERTZ)
16327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  de    qwerty T  Deutsch (QWERTY)
16427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka    //  en_US azerty T  English (US) (AZERTY)
165757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka    //  zz    azerty T  No language (AZERTY)    in system locale
16627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka
167ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka    public static String getSubtypeDisplayName(final InputMethodSubtype subtype, Resources res) {
168165725aba8a179440af9c93869b35f206b2e133fTadashi G. Takaoka        final String replacementString = (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15
169165725aba8a179440af9c93869b35f206b2e133fTadashi G. Takaoka                && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME))
1708e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka                ? subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)
1718e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka                : getSubtypeLocaleDisplayName(subtype.getLocale());
172757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka        final int nameResId = subtype.getNameResId();
173757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka        final RunInLocale<String> getSubtypeName = new RunInLocale<String>() {
174757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka            @Override
175757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka            protected String job(Resources res) {
176ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                try {
1778e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka                    return res.getString(nameResId, replacementString);
178ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                } catch (Resources.NotFoundException e) {
179ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                    // TODO: Remove this catch when InputMethodManager.getCurrentInputMethodSubtype
180ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                    // is fixed.
181ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                    Log.w(TAG, "Unknown subtype: mode=" + subtype.getMode()
182ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                            + " locale=" + subtype.getLocale()
183ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                            + " extra=" + subtype.getExtraValue()
184ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                            + "\n" + Utils.getStackTrace());
185ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                    return "";
186ca934420269e18c843181c0dc98cd61cce67dd19Tadashi G. Takaoka                }
187757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka            }
188757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka        };
189757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka        final Locale locale = isNoLanguage(subtype)
190757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka                ? res.getConfiguration().locale : getSubtypeLocale(subtype);
191757c12556b5336cce4962b18967a0da20c871329Tadashi G. Takaoka        return getSubtypeName.runInLocale(res, locale);
192cb389ef0d6e6eec737c249e1729c2a2cdc30f341Tadashi G. Takaoka    }
1938abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka
194f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka    public static boolean isNoLanguage(InputMethodSubtype subtype) {
195f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka        final String localeString = subtype.getLocale();
196f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka        return localeString.equals(NO_LANGUAGE);
1978abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka    }
1988abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka
199f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka    public static Locale getSubtypeLocale(InputMethodSubtype subtype) {
200f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka        final String localeString = subtype.getLocale();
201f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka        return LocaleUtils.constructLocaleFromString(localeString);
202f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka    }
203f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka
204bb17bafac3db7f54559e3d774069f0a915753cc3Tadashi G. Takaoka    public static String getKeyboardLayoutSetDisplayName(InputMethodSubtype subtype) {
20578173bdf535e38a4f9c3bcc8038151de86071728Tadashi G. Takaoka        final String layoutName = getKeyboardLayoutSetName(subtype);
2068e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka        return getKeyboardLayoutSetDisplayName(layoutName);
2078e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    }
2088e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka
2098e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka    public static String getKeyboardLayoutSetDisplayName(String layoutName) {
2108e50c5d198f65beb6679a9a1e0102e5fc52d7707Tadashi G. Takaoka        return sKeyboardLayoutToDisplayNameMap.get(layoutName);
211bb17bafac3db7f54559e3d774069f0a915753cc3Tadashi G. Takaoka    }
212bb17bafac3db7f54559e3d774069f0a915753cc3Tadashi G. Takaoka
213f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka    public static String getKeyboardLayoutSetName(InputMethodSubtype subtype) {
2147f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka        String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET);
2157f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka        if (keyboardLayoutSet == null) {
2167f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            // This subtype doesn't have a keyboardLayoutSet extra value, so lookup its keyboard
2177f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            // layout set in sLocaleAndExtraValueToKeyboardLayoutSetMap to keep it compatible with
2187f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            // pre-JellyBean.
2197f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            final String key = subtype.getLocale() + ":" + subtype.getExtraValue();
2207f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka            keyboardLayoutSet = sLocaleAndExtraValueToKeyboardLayoutSetMap.get(key);
2217f7947c97b141cbb338c5164e9e19d1ac9ff3d1cTadashi G. Takaoka        }
2228abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka        // TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is
2238abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka        // fixed.
224c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka        if (keyboardLayoutSet == null) {
225c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka            android.util.Log.w(TAG, "KeyboardLayoutSet not found, use QWERTY: " +
226b9fca7a192f3e448220fe79ea89d307f47b0d6b8Tadashi G. Takaoka                    "locale=" + subtype.getLocale() + " extraValue=" + subtype.getExtraValue());
22738026b4f03fb4d846b8613d889d68c439f6e30cbTadashi G. Takaoka            return QWERTY;
228c27fe6253c1d8b3ad3c2f891a48ec5c54d77a3f1Tadashi G. Takaoka        }
229f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka        return keyboardLayoutSet;
2308abde7db6bacbd5726a87e924ec8aea7fbb10d9aTadashi G. Takaoka    }
231e276d8ddaaff91d5940a71cefb5ecd94fd48ba98Tadashi G. Takaoka}
232