19cd11a9aa5ac74ca89432655d019f68d789bc405satok/* 29cd11a9aa5ac74ca89432655d019f68d789bc405satok * Copyright (C) 2010 The Android Open Source Project 39cd11a9aa5ac74ca89432655d019f68d789bc405satok * 49cd11a9aa5ac74ca89432655d019f68d789bc405satok * Licensed under the Apache License, Version 2.0 (the "License"); 59cd11a9aa5ac74ca89432655d019f68d789bc405satok * you may not use this file except in compliance with the License. 69cd11a9aa5ac74ca89432655d019f68d789bc405satok * You may obtain a copy of the License at 79cd11a9aa5ac74ca89432655d019f68d789bc405satok * 89cd11a9aa5ac74ca89432655d019f68d789bc405satok * http://www.apache.org/licenses/LICENSE-2.0 99cd11a9aa5ac74ca89432655d019f68d789bc405satok * 109cd11a9aa5ac74ca89432655d019f68d789bc405satok * Unless required by applicable law or agreed to in writing, software 119cd11a9aa5ac74ca89432655d019f68d789bc405satok * distributed under the License is distributed on an "AS IS" BASIS, 129cd11a9aa5ac74ca89432655d019f68d789bc405satok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139cd11a9aa5ac74ca89432655d019f68d789bc405satok * See the License for the specific language governing permissions and 149cd11a9aa5ac74ca89432655d019f68d789bc405satok * limitations under the License. 159cd11a9aa5ac74ca89432655d019f68d789bc405satok */ 169cd11a9aa5ac74ca89432655d019f68d789bc405satok 170417e4094713c5f4dac700b645000d0959bf62fasatokpackage com.android.settings.inputmethod; 189cd11a9aa5ac74ca89432655d019f68d789bc405satok 1991c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport android.annotation.NonNull; 2091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport android.annotation.Nullable; 210417e4094713c5f4dac700b645000d0959bf62fasatokimport android.content.ContentResolver; 2291c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport android.content.Context; 2374e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaokaimport android.content.SharedPreferences; 2491c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport android.content.res.Configuration; 2591c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport android.icu.text.ListFormatter; 269cd11a9aa5ac74ca89432655d019f68d789bc405satokimport android.provider.Settings; 273de7021756efd7fc9082b8768bc9a38fa310e7d8satokimport android.provider.Settings.SettingNotFoundException; 2839b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.Preference; 2939b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceScreen; 3039b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.TwoStatePreference; 319cd11a9aa5ac74ca89432655d019f68d789bc405satokimport android.text.TextUtils; 323de7021756efd7fc9082b8768bc9a38fa310e7d8satokimport android.util.Log; 339cd11a9aa5ac74ca89432655d019f68d789bc405satokimport android.view.inputmethod.InputMethodInfo; 349cd11a9aa5ac74ca89432655d019f68d789bc405satokimport android.view.inputmethod.InputMethodSubtype; 359cd11a9aa5ac74ca89432655d019f68d789bc405satok 3691c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport com.android.internal.app.LocaleHelper; 3774e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaokaimport com.android.internal.inputmethod.InputMethodUtils; 3874e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaokaimport com.android.settings.SettingsPreferenceFragment; 3974e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka 403de7021756efd7fc9082b8768bc9a38fa310e7d8satokimport java.util.HashMap; 419cd11a9aa5ac74ca89432655d019f68d789bc405satokimport java.util.HashSet; 429cd11a9aa5ac74ca89432655d019f68d789bc405satokimport java.util.List; 4391c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawaimport java.util.Locale; 44c88a7ff1efd10374974e45768bde1658cc1d8483satokimport java.util.Map; 459cd11a9aa5ac74ca89432655d019f68d789bc405satok 46d2dd7d33c9206f7aa29abbff48119d0f86ddfc36Tadashi G. Takaoka// TODO: Consolidate this with {@link InputMethodSettingValuesWrapper}. 47d2dd7d33c9206f7aa29abbff48119d0f86ddfc36Tadashi G. Takaokaclass InputMethodAndSubtypeUtil { 489cd11a9aa5ac74ca89432655d019f68d789bc405satok 493de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static final boolean DEBUG = false; 503de7021756efd7fc9082b8768bc9a38fa310e7d8satok static final String TAG = "InputMethdAndSubtypeUtil"; 513de7021756efd7fc9082b8768bc9a38fa310e7d8satok 523de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static final char INPUT_METHOD_SEPARATER = ':'; 533de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';'; 543de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static final int NOT_A_SUBTYPE_ID = -1; 553de7021756efd7fc9082b8768bc9a38fa310e7d8satok 563de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static final TextUtils.SimpleStringSplitter sStringInputMethodSplitter 573de7021756efd7fc9082b8768bc9a38fa310e7d8satok = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER); 583de7021756efd7fc9082b8768bc9a38fa310e7d8satok 593de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static final TextUtils.SimpleStringSplitter sStringInputMethodSubtypeSplitter 603de7021756efd7fc9082b8768bc9a38fa310e7d8satok = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER); 613de7021756efd7fc9082b8768bc9a38fa310e7d8satok 629a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka // InputMethods and subtypes are saved in the settings as follows: 639a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1 649a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka static String buildInputMethodsAndSubtypesString( 659a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashMap<String, HashSet<String>> imeToSubtypesMap) { 669a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final StringBuilder builder = new StringBuilder(); 679a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka for (final String imi : imeToSubtypesMap.keySet()) { 689a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (builder.length() > 0) { 69c88a7ff1efd10374974e45768bde1658cc1d8483satok builder.append(INPUT_METHOD_SEPARATER); 70c88a7ff1efd10374974e45768bde1658cc1d8483satok } 719a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashSet<String> subtypeIdSet = imeToSubtypesMap.get(imi); 729a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka builder.append(imi); 739a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka for (final String subtypeId : subtypeIdSet) { 749a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId); 759a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka } 76c88a7ff1efd10374974e45768bde1658cc1d8483satok } 779a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka return builder.toString(); 78c88a7ff1efd10374974e45768bde1658cc1d8483satok } 79c88a7ff1efd10374974e45768bde1658cc1d8483satok 809a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka private static String buildInputMethodsString(final HashSet<String> imiList) { 819a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final StringBuilder builder = new StringBuilder(); 829a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka for (final String imi : imiList) { 839a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (builder.length() > 0) { 84c88a7ff1efd10374974e45768bde1658cc1d8483satok builder.append(INPUT_METHOD_SEPARATER); 85c88a7ff1efd10374974e45768bde1658cc1d8483satok } 869a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka builder.append(imi); 87c88a7ff1efd10374974e45768bde1658cc1d8483satok } 889a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka return builder.toString(); 89c88a7ff1efd10374974e45768bde1658cc1d8483satok } 90c88a7ff1efd10374974e45768bde1658cc1d8483satok 9123bdc188438e28958c97ac252f59f5beefb38238satok private static int getInputMethodSubtypeSelected(ContentResolver resolver) { 923de7021756efd7fc9082b8768bc9a38fa310e7d8satok try { 933de7021756efd7fc9082b8768bc9a38fa310e7d8satok return Settings.Secure.getInt(resolver, 9423bdc188438e28958c97ac252f59f5beefb38238satok Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE); 953de7021756efd7fc9082b8768bc9a38fa310e7d8satok } catch (SettingNotFoundException e) { 9623bdc188438e28958c97ac252f59f5beefb38238satok return NOT_A_SUBTYPE_ID; 973de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 983de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 993de7021756efd7fc9082b8768bc9a38fa310e7d8satok 10023bdc188438e28958c97ac252f59f5beefb38238satok private static boolean isInputMethodSubtypeSelected(ContentResolver resolver) { 10123bdc188438e28958c97ac252f59f5beefb38238satok return getInputMethodSubtypeSelected(resolver) != NOT_A_SUBTYPE_ID; 10223bdc188438e28958c97ac252f59f5beefb38238satok } 10323bdc188438e28958c97ac252f59f5beefb38238satok 1043de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static void putSelectedInputMethodSubtype(ContentResolver resolver, int hashCode) { 1053de7021756efd7fc9082b8768bc9a38fa310e7d8satok Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, hashCode); 1063de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1073de7021756efd7fc9082b8768bc9a38fa310e7d8satok 1083de7021756efd7fc9082b8768bc9a38fa310e7d8satok // Needs to modify InputMethodManageService if you want to change the format of saved string. 1093de7021756efd7fc9082b8768bc9a38fa310e7d8satok private static HashMap<String, HashSet<String>> getEnabledInputMethodsAndSubtypeList( 1103de7021756efd7fc9082b8768bc9a38fa310e7d8satok ContentResolver resolver) { 1113de7021756efd7fc9082b8768bc9a38fa310e7d8satok final String enabledInputMethodsStr = Settings.Secure.getString( 1123de7021756efd7fc9082b8768bc9a38fa310e7d8satok resolver, Settings.Secure.ENABLED_INPUT_METHODS); 1133de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (DEBUG) { 1143de7021756efd7fc9082b8768bc9a38fa310e7d8satok Log.d(TAG, "--- Load enabled input methods: " + enabledInputMethodsStr); 1153de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1169a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka return parseInputMethodsAndSubtypesString(enabledInputMethodsStr); 1179a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka } 1183de7021756efd7fc9082b8768bc9a38fa310e7d8satok 1199a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka static HashMap<String, HashSet<String>> parseInputMethodsAndSubtypesString( 1209a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final String inputMethodsAndSubtypesString) { 1219a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashMap<String, HashSet<String>> subtypesMap = new HashMap<>(); 1229a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) { 1239a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka return subtypesMap; 1243de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1259a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka sStringInputMethodSplitter.setString(inputMethodsAndSubtypesString); 1263de7021756efd7fc9082b8768bc9a38fa310e7d8satok while (sStringInputMethodSplitter.hasNext()) { 1279a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final String nextImsStr = sStringInputMethodSplitter.next(); 1283de7021756efd7fc9082b8768bc9a38fa310e7d8satok sStringInputMethodSubtypeSplitter.setString(nextImsStr); 1293de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (sStringInputMethodSubtypeSplitter.hasNext()) { 1309a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashSet<String> subtypeIdSet = new HashSet<>(); 1319a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka // The first element is {@link InputMethodInfoId}. 1329a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final String imiId = sStringInputMethodSubtypeSplitter.next(); 1333de7021756efd7fc9082b8768bc9a38fa310e7d8satok while (sStringInputMethodSubtypeSplitter.hasNext()) { 1349a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka subtypeIdSet.add(sStringInputMethodSubtypeSplitter.next()); 1353de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1369a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka subtypesMap.put(imiId, subtypeIdSet); 1373de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1383de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1399a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka return subtypesMap; 1409a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka } 1419a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka 1429a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka static void enableInputMethodSubtypesOf(final ContentResolver resolver, final String imiId, 1439a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashSet<String> enabledSubtypeIdSet) { 1449a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashMap<String, HashSet<String>> enabledImeAndSubtypeIdsMap = 1459a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka getEnabledInputMethodsAndSubtypeList(resolver); 1469a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka enabledImeAndSubtypeIdsMap.put(imiId, enabledSubtypeIdSet); 1479a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final String enabledImesAndSubtypesString = buildInputMethodsAndSubtypesString( 1489a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka enabledImeAndSubtypeIdsMap); 1499a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka Settings.Secure.putString(resolver, 1509a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka Settings.Secure.ENABLED_INPUT_METHODS, enabledImesAndSubtypesString); 1513de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 1529cd11a9aa5ac74ca89432655d019f68d789bc405satok 153c88a7ff1efd10374974e45768bde1658cc1d8483satok private static HashSet<String> getDisabledSystemIMEs(ContentResolver resolver) { 154d2dd7d33c9206f7aa29abbff48119d0f86ddfc36Tadashi G. Takaoka HashSet<String> set = new HashSet<>(); 155c88a7ff1efd10374974e45768bde1658cc1d8483satok String disabledIMEsStr = Settings.Secure.getString( 156c88a7ff1efd10374974e45768bde1658cc1d8483satok resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS); 15710d2e1bc2f43fa3f39ea819e2eaf14c713c91a27satok if (TextUtils.isEmpty(disabledIMEsStr)) { 15810d2e1bc2f43fa3f39ea819e2eaf14c713c91a27satok return set; 15910d2e1bc2f43fa3f39ea819e2eaf14c713c91a27satok } 160c88a7ff1efd10374974e45768bde1658cc1d8483satok sStringInputMethodSplitter.setString(disabledIMEsStr); 161c88a7ff1efd10374974e45768bde1658cc1d8483satok while(sStringInputMethodSplitter.hasNext()) { 162c88a7ff1efd10374974e45768bde1658cc1d8483satok set.add(sStringInputMethodSplitter.next()); 163c88a7ff1efd10374974e45768bde1658cc1d8483satok } 164c88a7ff1efd10374974e45768bde1658cc1d8483satok return set; 165c88a7ff1efd10374974e45768bde1658cc1d8483satok } 166c88a7ff1efd10374974e45768bde1658cc1d8483satok 167d2dd7d33c9206f7aa29abbff48119d0f86ddfc36Tadashi G. Takaoka static void saveInputMethodSubtypeList(SettingsPreferenceFragment context, 168c88a7ff1efd10374974e45768bde1658cc1d8483satok ContentResolver resolver, List<InputMethodInfo> inputMethodInfos, 169c88a7ff1efd10374974e45768bde1658cc1d8483satok boolean hasHardKeyboard) { 1703de7021756efd7fc9082b8768bc9a38fa310e7d8satok String currentInputMethodId = Settings.Secure.getString(resolver, 1719cd11a9aa5ac74ca89432655d019f68d789bc405satok Settings.Secure.DEFAULT_INPUT_METHOD); 17223bdc188438e28958c97ac252f59f5beefb38238satok final int selectedInputMethodSubtype = getInputMethodSubtypeSelected(resolver); 1739a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashMap<String, HashSet<String>> enabledIMEsAndSubtypesMap = 174c88a7ff1efd10374974e45768bde1658cc1d8483satok getEnabledInputMethodsAndSubtypeList(resolver); 1759a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashSet<String> disabledSystemIMEs = getDisabledSystemIMEs(resolver); 1769cd11a9aa5ac74ca89432655d019f68d789bc405satok 177d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok boolean needsToResetSelectedSubtype = false; 1789a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka for (final InputMethodInfo imi : inputMethodInfos) { 179c88a7ff1efd10374974e45768bde1658cc1d8483satok final String imiId = imi.getId(); 1809a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final Preference pref = context.findPreference(imiId); 1819a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (pref == null) { 1829a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka continue; 1839a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka } 18474e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka // In the choose input method screen or in the subtype enabler screen, 18574e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka // <code>pref</code> is an instance of TwoStatePreference. 18674e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka final boolean isImeChecked = (pref instanceof TwoStatePreference) ? 18774e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka ((TwoStatePreference) pref).isChecked() 1889a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka : enabledIMEsAndSubtypesMap.containsKey(imiId); 1894c5fdcc3f70ac5496b21d7db57f62ee9db4e6a19satok final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId); 190993f6ecf4065501433271b5fd5daf21a6f3ae586Satoshi Kataoka final boolean systemIme = InputMethodUtils.isSystemIme(imi); 191993f6ecf4065501433271b5fd5daf21a6f3ae586Satoshi Kataoka if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance( 192993f6ecf4065501433271b5fd5daf21a6f3ae586Satoshi Kataoka context.getActivity()).isAlwaysCheckedIme(imi, context.getActivity())) 193472c3c93fc61b797b3ee22352a876ccae3eeb153satok || isImeChecked) { 1949a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (!enabledIMEsAndSubtypesMap.containsKey(imiId)) { 195c88a7ff1efd10374974e45768bde1658cc1d8483satok // imiId has just been enabled 1969a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka enabledIMEsAndSubtypesMap.put(imiId, new HashSet<String>()); 197c88a7ff1efd10374974e45768bde1658cc1d8483satok } 1989a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final HashSet<String> subtypesSet = enabledIMEsAndSubtypesMap.get(imiId); 199517c10dd9cc8f1b52cbe818595fe124e9c0af813satok 200d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok boolean subtypePrefFound = false; 2015a813ba7f99f1c797ead4a58fdf05f91296158a4Ken Wakasa final int subtypeCount = imi.getSubtypeCount(); 2025a813ba7f99f1c797ead4a58fdf05f91296158a4Ken Wakasa for (int i = 0; i < subtypeCount; ++i) { 2039a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final InputMethodSubtype subtype = imi.getSubtypeAt(i); 204c88a7ff1efd10374974e45768bde1658cc1d8483satok final String subtypeHashCodeStr = String.valueOf(subtype.hashCode()); 2051f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka final TwoStatePreference subtypePref = (TwoStatePreference) context 2061f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka .findPreference(imiId + subtypeHashCodeStr); 207c88a7ff1efd10374974e45768bde1658cc1d8483satok // In the Configure input method screen which does not have subtype preferences. 2089a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (subtypePref == null) { 2099a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka continue; 2109a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka } 211d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok if (!subtypePrefFound) { 2121f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka // Once subtype preference is found, subtypeSet needs to be cleared. 213d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok // Because of system change, hashCode value could have been changed. 214517c10dd9cc8f1b52cbe818595fe124e9c0af813satok subtypesSet.clear(); 215d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok // If selected subtype preference is disabled, needs to reset. 216d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok needsToResetSelectedSubtype = true; 217d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok subtypePrefFound = true; 218517c10dd9cc8f1b52cbe818595fe124e9c0af813satok } 2196452b84763f864139a3744bd3406f72a0014301aYohei Yukawa // Checking <code>subtypePref.isEnabled()</code> is insufficient to determine 2206452b84763f864139a3744bd3406f72a0014301aYohei Yukawa // whether the user manually enabled this subtype or not. Implicitly-enabled 2216452b84763f864139a3744bd3406f72a0014301aYohei Yukawa // subtypes are also checked just as an indicator to users. We also need to 2226452b84763f864139a3744bd3406f72a0014301aYohei Yukawa // check <code>subtypePref.isEnabled()</code> so that only manually enabled 2236452b84763f864139a3744bd3406f72a0014301aYohei Yukawa // subtypes can be saved here. 2246452b84763f864139a3744bd3406f72a0014301aYohei Yukawa if (subtypePref.isEnabled() && subtypePref.isChecked()) { 225c88a7ff1efd10374974e45768bde1658cc1d8483satok subtypesSet.add(subtypeHashCodeStr); 22623bdc188438e28958c97ac252f59f5beefb38238satok if (isCurrentInputMethod) { 22723bdc188438e28958c97ac252f59f5beefb38238satok if (selectedInputMethodSubtype == subtype.hashCode()) { 228d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok // Selected subtype is still enabled, there is no need to reset 229d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok // selected subtype. 230d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok needsToResetSelectedSubtype = false; 23123bdc188438e28958c97ac252f59f5beefb38238satok } 2323de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 233c88a7ff1efd10374974e45768bde1658cc1d8483satok } else { 234c88a7ff1efd10374974e45768bde1658cc1d8483satok subtypesSet.remove(subtypeHashCodeStr); 2353de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 2363de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 237c88a7ff1efd10374974e45768bde1658cc1d8483satok } else { 2389a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka enabledIMEsAndSubtypesMap.remove(imiId); 239c88a7ff1efd10374974e45768bde1658cc1d8483satok if (isCurrentInputMethod) { 240c88a7ff1efd10374974e45768bde1658cc1d8483satok // We are processing the current input method, but found that it's not enabled. 241c88a7ff1efd10374974e45768bde1658cc1d8483satok // This means that the current input method has been uninstalled. 242c88a7ff1efd10374974e45768bde1658cc1d8483satok // If currentInputMethod is already uninstalled, InputMethodManagerService will 243c88a7ff1efd10374974e45768bde1658cc1d8483satok // find the applicable IME from the history and the system locale. 244c88a7ff1efd10374974e45768bde1658cc1d8483satok if (DEBUG) { 245c88a7ff1efd10374974e45768bde1658cc1d8483satok Log.d(TAG, "Current IME was uninstalled or disabled."); 246c88a7ff1efd10374974e45768bde1658cc1d8483satok } 247062c3c3c3d5890e85bff61ca067860641aa8f8f8satok currentInputMethodId = null; 2485fd39cafe1de792300e9e3dd60258a1ce5079f73satok } 2499cd11a9aa5ac74ca89432655d019f68d789bc405satok } 2509cd11a9aa5ac74ca89432655d019f68d789bc405satok // If it's a disabled system ime, add it to the disabled list so that it 2519cd11a9aa5ac74ca89432655d019f68d789bc405satok // doesn't get enabled automatically on any changes to the package list 252c88a7ff1efd10374974e45768bde1658cc1d8483satok if (systemIme && hasHardKeyboard) { 253c88a7ff1efd10374974e45768bde1658cc1d8483satok if (disabledSystemIMEs.contains(imiId)) { 254c88a7ff1efd10374974e45768bde1658cc1d8483satok if (isImeChecked) { 255c88a7ff1efd10374974e45768bde1658cc1d8483satok disabledSystemIMEs.remove(imiId); 256c88a7ff1efd10374974e45768bde1658cc1d8483satok } 257c88a7ff1efd10374974e45768bde1658cc1d8483satok } else { 258c88a7ff1efd10374974e45768bde1658cc1d8483satok if (!isImeChecked) { 259c88a7ff1efd10374974e45768bde1658cc1d8483satok disabledSystemIMEs.add(imiId); 260c88a7ff1efd10374974e45768bde1658cc1d8483satok } 261c88a7ff1efd10374974e45768bde1658cc1d8483satok } 2629cd11a9aa5ac74ca89432655d019f68d789bc405satok } 2639cd11a9aa5ac74ca89432655d019f68d789bc405satok } 2649cd11a9aa5ac74ca89432655d019f68d789bc405satok 2659a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final String enabledIMEsAndSubtypesString = buildInputMethodsAndSubtypesString( 2669a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka enabledIMEsAndSubtypesMap); 2679a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka final String disabledSystemIMEsString = buildInputMethodsString(disabledSystemIMEs); 2683de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (DEBUG) { 2699a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka Log.d(TAG, "--- Save enabled inputmethod settings. :" + enabledIMEsAndSubtypesString); 2709a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka Log.d(TAG, "--- Save disabled system inputmethod settings. :" 2719a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka + disabledSystemIMEsString); 2723de7021756efd7fc9082b8768bc9a38fa310e7d8satok Log.d(TAG, "--- Save default inputmethod settings. :" + currentInputMethodId); 273d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok Log.d(TAG, "--- Needs to reset the selected subtype :" + needsToResetSelectedSubtype); 274d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok Log.d(TAG, "--- Subtype is selected :" + isInputMethodSubtypeSelected(resolver)); 2753de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 2763de7021756efd7fc9082b8768bc9a38fa310e7d8satok 27723bdc188438e28958c97ac252f59f5beefb38238satok // Redefines SelectedSubtype when all subtypes are unchecked or there is no subtype 27823bdc188438e28958c97ac252f59f5beefb38238satok // selected. And if the selected subtype of the current input method was disabled, 27923bdc188438e28958c97ac252f59f5beefb38238satok // We should reset the selected input method's subtype. 280d7973d1c0ae6ad6c676f19d5e0e030152c50784asatok if (needsToResetSelectedSubtype || !isInputMethodSubtypeSelected(resolver)) { 2813de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (DEBUG) { 282c88a7ff1efd10374974e45768bde1658cc1d8483satok Log.d(TAG, "--- Reset inputmethod subtype because it's not defined."); 2833de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 284c88a7ff1efd10374974e45768bde1658cc1d8483satok putSelectedInputMethodSubtype(resolver, NOT_A_SUBTYPE_ID); 2853de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 2863de7021756efd7fc9082b8768bc9a38fa310e7d8satok 2870417e4094713c5f4dac700b645000d0959bf62fasatok Settings.Secure.putString(resolver, 2889a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka Settings.Secure.ENABLED_INPUT_METHODS, enabledIMEsAndSubtypesString); 2899a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka if (disabledSystemIMEsString.length() > 0) { 290c88a7ff1efd10374974e45768bde1658cc1d8483satok Settings.Secure.putString(resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, 2919a8b4f239f219bb2cd2d08470b8c858fd74341e7Tadashi G. Takaoka disabledSystemIMEsString); 292c88a7ff1efd10374974e45768bde1658cc1d8483satok } 2935fd39cafe1de792300e9e3dd60258a1ce5079f73satok // If the current input method is unset, InputMethodManagerService will find the applicable 2945fd39cafe1de792300e9e3dd60258a1ce5079f73satok // IME from the history and the system locale. 2950417e4094713c5f4dac700b645000d0959bf62fasatok Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, 2963de7021756efd7fc9082b8768bc9a38fa310e7d8satok currentInputMethodId != null ? currentInputMethodId : ""); 2979cd11a9aa5ac74ca89432655d019f68d789bc405satok } 2989cd11a9aa5ac74ca89432655d019f68d789bc405satok 2993460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka static void loadInputMethodSubtypeList(final SettingsPreferenceFragment context, 3003460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final ContentResolver resolver, final List<InputMethodInfo> inputMethodInfos, 301c88a7ff1efd10374974e45768bde1658cc1d8483satok final Map<String, List<Preference>> inputMethodPrefsMap) { 3023460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final HashMap<String, HashSet<String>> enabledSubtypes = 3034c5fdcc3f70ac5496b21d7db57f62ee9db4e6a19satok getEnabledInputMethodsAndSubtypeList(resolver); 3049cd11a9aa5ac74ca89432655d019f68d789bc405satok 3053460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka for (final InputMethodInfo imi : inputMethodInfos) { 306c88a7ff1efd10374974e45768bde1658cc1d8483satok final String imiId = imi.getId(); 3073460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final Preference pref = context.findPreference(imiId); 3081f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka if (pref instanceof TwoStatePreference) { 3091f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka final TwoStatePreference subtypePref = (TwoStatePreference) pref; 3103460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final boolean isEnabled = enabledSubtypes.containsKey(imiId); 3111f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka subtypePref.setChecked(isEnabled); 312c88a7ff1efd10374974e45768bde1658cc1d8483satok if (inputMethodPrefsMap != null) { 3133460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka for (final Preference childPref: inputMethodPrefsMap.get(imiId)) { 314c88a7ff1efd10374974e45768bde1658cc1d8483satok childPref.setEnabled(isEnabled); 315c88a7ff1efd10374974e45768bde1658cc1d8483satok } 316c88a7ff1efd10374974e45768bde1658cc1d8483satok } 317c88a7ff1efd10374974e45768bde1658cc1d8483satok setSubtypesPreferenceEnabled(context, inputMethodInfos, imiId, isEnabled); 3189cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3199cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3207ea58d31646bcfbcdd9ddd0bfdc685ed7ab3f1d8satok updateSubtypesPreferenceChecked(context, inputMethodInfos, enabledSubtypes); 3219cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3229cd11a9aa5ac74ca89432655d019f68d789bc405satok 3233460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka static void setSubtypesPreferenceEnabled(final SettingsPreferenceFragment context, 3243460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final List<InputMethodInfo> inputMethodProperties, final String id, 3253460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final boolean enabled) { 3263460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); 3273460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka for (final InputMethodInfo imi : inputMethodProperties) { 3289cd11a9aa5ac74ca89432655d019f68d789bc405satok if (id.equals(imi.getId())) { 3295a813ba7f99f1c797ead4a58fdf05f91296158a4Ken Wakasa final int subtypeCount = imi.getSubtypeCount(); 3305a813ba7f99f1c797ead4a58fdf05f91296158a4Ken Wakasa for (int i = 0; i < subtypeCount; ++i) { 3313460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final InputMethodSubtype subtype = imi.getSubtypeAt(i); 3321f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka final TwoStatePreference pref = (TwoStatePreference) preferenceScreen 3333460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka .findPreference(id + subtype.hashCode()); 3343de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (pref != null) { 3353de7021756efd7fc9082b8768bc9a38fa310e7d8satok pref.setEnabled(enabled); 3363de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 3379cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3389cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3399cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3409cd11a9aa5ac74ca89432655d019f68d789bc405satok } 3413de7021756efd7fc9082b8768bc9a38fa310e7d8satok 3423460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka private static void updateSubtypesPreferenceChecked(final SettingsPreferenceFragment context, 3433460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final List<InputMethodInfo> inputMethodProperties, 3443460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final HashMap<String, HashSet<String>> enabledSubtypes) { 3453460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); 3463460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka for (final InputMethodInfo imi : inputMethodProperties) { 3473460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final String id = imi.getId(); 3483460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka if (!enabledSubtypes.containsKey(id)) { 3493460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka // There is no need to enable/disable subtypes of disabled IMEs. 3503460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka continue; 3513460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka } 3527ea58d31646bcfbcdd9ddd0bfdc685ed7ab3f1d8satok final HashSet<String> enabledSubtypesSet = enabledSubtypes.get(id); 3535a813ba7f99f1c797ead4a58fdf05f91296158a4Ken Wakasa final int subtypeCount = imi.getSubtypeCount(); 3545a813ba7f99f1c797ead4a58fdf05f91296158a4Ken Wakasa for (int i = 0; i < subtypeCount; ++i) { 3553460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final InputMethodSubtype subtype = imi.getSubtypeAt(i); 3563460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka final String hashCode = String.valueOf(subtype.hashCode()); 3573de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (DEBUG) { 3583de7021756efd7fc9082b8768bc9a38fa310e7d8satok Log.d(TAG, "--- Set checked state: " + "id" + ", " + hashCode + ", " 3593de7021756efd7fc9082b8768bc9a38fa310e7d8satok + enabledSubtypesSet.contains(hashCode)); 3603de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 3611f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka final TwoStatePreference pref = (TwoStatePreference) preferenceScreen 3623460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka .findPreference(id + hashCode); 3633de7021756efd7fc9082b8768bc9a38fa310e7d8satok if (pref != null) { 3643de7021756efd7fc9082b8768bc9a38fa310e7d8satok pref.setChecked(enabledSubtypesSet.contains(hashCode)); 3653de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 3663de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 3673de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 3683de7021756efd7fc9082b8768bc9a38fa310e7d8satok } 36974e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka 37074e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka static void removeUnnecessaryNonPersistentPreference(final Preference pref) { 37174e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka final String key = pref.getKey(); 37274e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka if (pref.isPersistent() || key == null) { 37374e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka return; 37474e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka } 37574e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka final SharedPreferences prefs = pref.getSharedPreferences(); 37674e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka if (prefs != null && prefs.contains(key)) { 37774e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka prefs.edit().remove(key).apply(); 37874e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka } 37974e7c3e3601f4808854cf12bffe11ebf4c6ea8abTadashi G. Takaoka } 38091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa 38191c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa @NonNull 38291c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa static String getSubtypeLocaleNameAsSentence(@Nullable InputMethodSubtype subtype, 38391c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa @NonNull final Context context, @NonNull final InputMethodInfo inputMethodInfo) { 38491c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa if (subtype == null) { 38591c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return ""; 38691c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 38791c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final Locale locale = getDisplayLocale(context); 38891c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final CharSequence subtypeName = subtype.getDisplayName(context, 38991c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() 39091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa .applicationInfo); 39191c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return LocaleHelper.toSentenceCase(subtypeName.toString(), locale); 39291c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 39391c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa 39491c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa @NonNull 39591c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa static String getSubtypeLocaleNameListAsSentence( 39691c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa @NonNull final List<InputMethodSubtype> subtypes, @NonNull final Context context, 39791c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa @NonNull final InputMethodInfo inputMethodInfo) { 39891c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa if (subtypes.isEmpty()) { 39991c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return ""; 40091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 40191c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final Locale locale = getDisplayLocale(context); 40291c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final int subtypeCount = subtypes.size(); 40391c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final CharSequence[] subtypeNames = new CharSequence[subtypeCount]; 40491c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa for (int i = 0; i < subtypeCount; i++) { 40591c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa subtypeNames[i] = subtypes.get(i).getDisplayName(context, 40691c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() 40791c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa .applicationInfo); 40891c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 40991c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return LocaleHelper.toSentenceCase( 41091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa ListFormatter.getInstance(locale).format(subtypeNames), locale); 41191c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 41291c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa 41391c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa @NonNull 41491c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa private static Locale getDisplayLocale(@Nullable final Context context) { 41591c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa if (context == null) { 41691c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return Locale.getDefault(); 41791c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 41891c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa if (context.getResources() == null) { 41991c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return Locale.getDefault(); 42091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 42191c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final Configuration configuration = context.getResources().getConfiguration(); 42291c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa if (configuration == null) { 42391c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return Locale.getDefault(); 42491c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 42591c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa final Locale configurationLocale = configuration.getLocales().get(0); 42691c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa if (configurationLocale == null) { 42791c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return Locale.getDefault(); 42891c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 42991c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa return configurationLocale; 43091c23ca03f9ffa9ac9f2644e50e51e481a423662Yohei Yukawa } 4319cd11a9aa5ac74ca89432655d019f68d789bc405satok} 432