InputMethodAndSubtypeUtil.java revision b8592357c37e681ba709b524a7202b7787f35e5a
1b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler/* 2b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * Copyright (C) 2017 The Android Open Source Project 3b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * 4b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * Licensed under the Apache License, Version 2.0 (the "License"); 5b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * you may not use this file except in compliance with the License. 6b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * You may obtain a copy of the License at 7b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * 8b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * http://www.apache.org/licenses/LICENSE-2.0 9b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * 10b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * Unless required by applicable law or agreed to in writing, software 11b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * distributed under the License is distributed on an "AS IS" BASIS, 12b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * See the License for the specific language governing permissions and 14b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler * limitations under the License 15b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler */ 16b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 17b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerpackage com.android.settingslib.inputmethod; 18b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 19b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.annotation.NonNull; 20b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.annotation.Nullable; 21b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.content.ContentResolver; 22b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.content.Context; 23b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.content.SharedPreferences; 24b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.content.res.Configuration; 25b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.icu.text.ListFormatter; 26b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.provider.Settings; 27b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.provider.Settings.SettingNotFoundException; 28b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.support.v14.preference.PreferenceFragment; 29b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.support.v7.preference.Preference; 30b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.support.v7.preference.PreferenceScreen; 31b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.support.v7.preference.TwoStatePreference; 32b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.text.TextUtils; 33b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.util.Log; 34b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.view.inputmethod.InputMethodInfo; 35b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport android.view.inputmethod.InputMethodSubtype; 36b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 37b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport com.android.internal.app.LocaleHelper; 38b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport com.android.internal.inputmethod.InputMethodUtils; 39b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 40b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport java.util.HashMap; 41b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport java.util.HashSet; 42b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport java.util.List; 43b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport java.util.Locale; 44b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerimport java.util.Map; 45b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 46b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler// TODO: Consolidate this with {@link InputMethodSettingValuesWrapper}. 47b8592357c37e681ba709b524a7202b7787f35e5aTony Mantlerpublic class InputMethodAndSubtypeUtil { 48b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 49b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final boolean DEBUG = false; 50b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final String TAG = "InputMethdAndSubtypeUtl"; 51b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 52b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final char INPUT_METHOD_SEPARATER = ':'; 53b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';'; 54b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final int NOT_A_SUBTYPE_ID = -1; 55b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 56b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final TextUtils.SimpleStringSplitter sStringInputMethodSplitter 57b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER); 58b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 59b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static final TextUtils.SimpleStringSplitter sStringInputMethodSubtypeSplitter 60b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER); 61b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 62b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // InputMethods and subtypes are saved in the settings as follows: 63b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1 64b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static String buildInputMethodsAndSubtypesString( 65b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashMap<String, HashSet<String>> imeToSubtypesMap) { 66b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final StringBuilder builder = new StringBuilder(); 67b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final String imi : imeToSubtypesMap.keySet()) { 68b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (builder.length() > 0) { 69b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler builder.append(INPUT_METHOD_SEPARATER); 70b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 71b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashSet<String> subtypeIdSet = imeToSubtypesMap.get(imi); 72b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler builder.append(imi); 73b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final String subtypeId : subtypeIdSet) { 74b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId); 75b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 76b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 77b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return builder.toString(); 78b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 79b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 80b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static String buildInputMethodsString(final HashSet<String> imiList) { 81b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final StringBuilder builder = new StringBuilder(); 82b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final String imi : imiList) { 83b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (builder.length() > 0) { 84b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler builder.append(INPUT_METHOD_SEPARATER); 85b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 86b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler builder.append(imi); 87b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 88b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return builder.toString(); 89b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 90b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 91b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static int getInputMethodSubtypeSelected(ContentResolver resolver) { 92b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler try { 93b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return Settings.Secure.getInt(resolver, 94b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE); 95b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } catch (SettingNotFoundException e) { 96b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return NOT_A_SUBTYPE_ID; 97b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 98b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 99b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 100b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static boolean isInputMethodSubtypeSelected(ContentResolver resolver) { 101b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return getInputMethodSubtypeSelected(resolver) != NOT_A_SUBTYPE_ID; 102b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 103b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 104b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static void putSelectedInputMethodSubtype(ContentResolver resolver, int hashCode) { 105b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, hashCode); 106b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 107b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 108b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // Needs to modify InputMethodManageService if you want to change the format of saved string. 109b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static HashMap<String, HashSet<String>> getEnabledInputMethodsAndSubtypeList( 110b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler ContentResolver resolver) { 111b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String enabledInputMethodsStr = Settings.Secure.getString( 112b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler resolver, Settings.Secure.ENABLED_INPUT_METHODS); 113b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (DEBUG) { 114b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Load enabled input methods: " + enabledInputMethodsStr); 115b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 116b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return parseInputMethodsAndSubtypesString(enabledInputMethodsStr); 117b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 118b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 119b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static HashMap<String, HashSet<String>> parseInputMethodsAndSubtypesString( 120b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String inputMethodsAndSubtypesString) { 121b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashMap<String, HashSet<String>> subtypesMap = new HashMap<>(); 122b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) { 123b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return subtypesMap; 124b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 125b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler sStringInputMethodSplitter.setString(inputMethodsAndSubtypesString); 126b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler while (sStringInputMethodSplitter.hasNext()) { 127b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String nextImsStr = sStringInputMethodSplitter.next(); 128b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler sStringInputMethodSubtypeSplitter.setString(nextImsStr); 129b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (sStringInputMethodSubtypeSplitter.hasNext()) { 130b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashSet<String> subtypeIdSet = new HashSet<>(); 131b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // The first element is {@link InputMethodInfoId}. 132b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String imiId = sStringInputMethodSubtypeSplitter.next(); 133b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler while (sStringInputMethodSubtypeSplitter.hasNext()) { 134b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypeIdSet.add(sStringInputMethodSubtypeSplitter.next()); 135b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 136b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypesMap.put(imiId, subtypeIdSet); 137b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 138b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 139b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return subtypesMap; 140b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 141b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 142b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static HashSet<String> getDisabledSystemIMEs(ContentResolver resolver) { 143b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler HashSet<String> set = new HashSet<>(); 144b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler String disabledIMEsStr = Settings.Secure.getString( 145b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS); 146b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (TextUtils.isEmpty(disabledIMEsStr)) { 147b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return set; 148b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 149b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler sStringInputMethodSplitter.setString(disabledIMEsStr); 150b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler while(sStringInputMethodSplitter.hasNext()) { 151b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler set.add(sStringInputMethodSplitter.next()); 152b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 153b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return set; 154b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 155b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 156b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler public static void saveInputMethodSubtypeList(PreferenceFragment context, 157b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler ContentResolver resolver, List<InputMethodInfo> inputMethodInfos, 158b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler boolean hasHardKeyboard) { 159b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler String currentInputMethodId = Settings.Secure.getString(resolver, 160b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.DEFAULT_INPUT_METHOD); 161b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final int selectedInputMethodSubtype = getInputMethodSubtypeSelected(resolver); 162b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashMap<String, HashSet<String>> enabledIMEsAndSubtypesMap = 163b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler getEnabledInputMethodsAndSubtypeList(resolver); 164b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashSet<String> disabledSystemIMEs = getDisabledSystemIMEs(resolver); 165b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 166b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler boolean needsToResetSelectedSubtype = false; 167b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final InputMethodInfo imi : inputMethodInfos) { 168b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String imiId = imi.getId(); 169b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Preference pref = context.findPreference(imiId); 170b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (pref == null) { 171b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler continue; 172b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 173b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // In the choose input method screen or in the subtype enabler screen, 174b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // <code>pref</code> is an instance of TwoStatePreference. 175b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final boolean isImeChecked = (pref instanceof TwoStatePreference) ? 176b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler ((TwoStatePreference) pref).isChecked() 177b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler : enabledIMEsAndSubtypesMap.containsKey(imiId); 178b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId); 179b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final boolean systemIme = InputMethodUtils.isSystemIme(imi); 180b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance( 181b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler context.getActivity()).isAlwaysCheckedIme(imi, context.getActivity())) 182b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler || isImeChecked) { 183b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (!enabledIMEsAndSubtypesMap.containsKey(imiId)) { 184b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // imiId has just been enabled 185b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler enabledIMEsAndSubtypesMap.put(imiId, new HashSet<>()); 186b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 187b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashSet<String> subtypesSet = enabledIMEsAndSubtypesMap.get(imiId); 188b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 189b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler boolean subtypePrefFound = false; 190b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final int subtypeCount = imi.getSubtypeCount(); 191b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (int i = 0; i < subtypeCount; ++i) { 192b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final InputMethodSubtype subtype = imi.getSubtypeAt(i); 193b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String subtypeHashCodeStr = String.valueOf(subtype.hashCode()); 194b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final TwoStatePreference subtypePref = (TwoStatePreference) context 195b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler .findPreference(imiId + subtypeHashCodeStr); 196b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // In the Configure input method screen which does not have subtype preferences. 197b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (subtypePref == null) { 198b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler continue; 199b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 200b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (!subtypePrefFound) { 201b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // Once subtype preference is found, subtypeSet needs to be cleared. 202b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // Because of system change, hashCode value could have been changed. 203b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypesSet.clear(); 204b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // If selected subtype preference is disabled, needs to reset. 205b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler needsToResetSelectedSubtype = true; 206b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypePrefFound = true; 207b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 208b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // Checking <code>subtypePref.isEnabled()</code> is insufficient to determine 209b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // whether the user manually enabled this subtype or not. Implicitly-enabled 210b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // subtypes are also checked just as an indicator to users. We also need to 211b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // check <code>subtypePref.isEnabled()</code> so that only manually enabled 212b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // subtypes can be saved here. 213b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (subtypePref.isEnabled() && subtypePref.isChecked()) { 214b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypesSet.add(subtypeHashCodeStr); 215b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (isCurrentInputMethod) { 216b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (selectedInputMethodSubtype == subtype.hashCode()) { 217b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // Selected subtype is still enabled, there is no need to reset 218b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // selected subtype. 219b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler needsToResetSelectedSubtype = false; 220b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 221b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 222b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } else { 223b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypesSet.remove(subtypeHashCodeStr); 224b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 225b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 226b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } else { 227b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler enabledIMEsAndSubtypesMap.remove(imiId); 228b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (isCurrentInputMethod) { 229b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // We are processing the current input method, but found that it's not enabled. 230b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // This means that the current input method has been uninstalled. 231b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // If currentInputMethod is already uninstalled, InputMethodManagerService will 232b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // find the applicable IME from the history and the system locale. 233b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (DEBUG) { 234b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "Current IME was uninstalled or disabled."); 235b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 236b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler currentInputMethodId = null; 237b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 238b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 239b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // If it's a disabled system ime, add it to the disabled list so that it 240b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // doesn't get enabled automatically on any changes to the package list 241b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (systemIme && hasHardKeyboard) { 242b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (disabledSystemIMEs.contains(imiId)) { 243b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (isImeChecked) { 244b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler disabledSystemIMEs.remove(imiId); 245b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 246b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } else { 247b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (!isImeChecked) { 248b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler disabledSystemIMEs.add(imiId); 249b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 250b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 251b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 252b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 253b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 254b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String enabledIMEsAndSubtypesString = buildInputMethodsAndSubtypesString( 255b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler enabledIMEsAndSubtypesMap); 256b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String disabledSystemIMEsString = buildInputMethodsString(disabledSystemIMEs); 257b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (DEBUG) { 258b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Save enabled inputmethod settings. :" + enabledIMEsAndSubtypesString); 259b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Save disabled system inputmethod settings. :" 260b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler + disabledSystemIMEsString); 261b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Save default inputmethod settings. :" + currentInputMethodId); 262b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Needs to reset the selected subtype :" + needsToResetSelectedSubtype); 263b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Subtype is selected :" + isInputMethodSubtypeSelected(resolver)); 264b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 265b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 266b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // Redefines SelectedSubtype when all subtypes are unchecked or there is no subtype 267b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // selected. And if the selected subtype of the current input method was disabled, 268b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // We should reset the selected input method's subtype. 269b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (needsToResetSelectedSubtype || !isInputMethodSubtypeSelected(resolver)) { 270b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (DEBUG) { 271b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Reset inputmethod subtype because it's not defined."); 272b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 273b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler putSelectedInputMethodSubtype(resolver, NOT_A_SUBTYPE_ID); 274b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 275b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 276b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.putString(resolver, 277b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.ENABLED_INPUT_METHODS, enabledIMEsAndSubtypesString); 278b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (disabledSystemIMEsString.length() > 0) { 279b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.putString(resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, 280b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler disabledSystemIMEsString); 281b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 282b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // If the current input method is unset, InputMethodManagerService will find the applicable 283b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // IME from the history and the system locale. 284b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, 285b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler currentInputMethodId != null ? currentInputMethodId : ""); 286b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 287b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 288b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler public static void loadInputMethodSubtypeList(final PreferenceFragment context, 289b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final ContentResolver resolver, final List<InputMethodInfo> inputMethodInfos, 290b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Map<String, List<Preference>> inputMethodPrefsMap) { 291b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashMap<String, HashSet<String>> enabledSubtypes = 292b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler getEnabledInputMethodsAndSubtypeList(resolver); 293b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 294b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final InputMethodInfo imi : inputMethodInfos) { 295b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String imiId = imi.getId(); 296b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Preference pref = context.findPreference(imiId); 297b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (pref instanceof TwoStatePreference) { 298b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final TwoStatePreference subtypePref = (TwoStatePreference) pref; 299b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final boolean isEnabled = enabledSubtypes.containsKey(imiId); 300b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypePref.setChecked(isEnabled); 301b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (inputMethodPrefsMap != null) { 302b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final Preference childPref: inputMethodPrefsMap.get(imiId)) { 303b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler childPref.setEnabled(isEnabled); 304b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 305b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 306b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler setSubtypesPreferenceEnabled(context, inputMethodInfos, imiId, isEnabled); 307b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 308b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 309b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler updateSubtypesPreferenceChecked(context, inputMethodInfos, enabledSubtypes); 310b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 311b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 312b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static void setSubtypesPreferenceEnabled(final PreferenceFragment context, 313b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final List<InputMethodInfo> inputMethodProperties, final String id, 314b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final boolean enabled) { 315b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); 316b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final InputMethodInfo imi : inputMethodProperties) { 317b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (id.equals(imi.getId())) { 318b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final int subtypeCount = imi.getSubtypeCount(); 319b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (int i = 0; i < subtypeCount; ++i) { 320b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final InputMethodSubtype subtype = imi.getSubtypeAt(i); 321b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final TwoStatePreference pref = (TwoStatePreference) preferenceScreen 322b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler .findPreference(id + subtype.hashCode()); 323b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (pref != null) { 324b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler pref.setEnabled(enabled); 325b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 326b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 327b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 328b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 329b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 330b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 331b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static void updateSubtypesPreferenceChecked(final PreferenceFragment context, 332b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final List<InputMethodInfo> inputMethodProperties, 333b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashMap<String, HashSet<String>> enabledSubtypes) { 334b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); 335b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (final InputMethodInfo imi : inputMethodProperties) { 336b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String id = imi.getId(); 337b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (!enabledSubtypes.containsKey(id)) { 338b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler // There is no need to enable/disable subtypes of disabled IMEs. 339b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler continue; 340b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 341b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final HashSet<String> enabledSubtypesSet = enabledSubtypes.get(id); 342b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final int subtypeCount = imi.getSubtypeCount(); 343b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (int i = 0; i < subtypeCount; ++i) { 344b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final InputMethodSubtype subtype = imi.getSubtypeAt(i); 345b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String hashCode = String.valueOf(subtype.hashCode()); 346b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (DEBUG) { 347b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler Log.d(TAG, "--- Set checked state: " + "id" + ", " + hashCode + ", " 348b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler + enabledSubtypesSet.contains(hashCode)); 349b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 350b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final TwoStatePreference pref = (TwoStatePreference) preferenceScreen 351b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler .findPreference(id + hashCode); 352b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (pref != null) { 353b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler pref.setChecked(enabledSubtypesSet.contains(hashCode)); 354b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 355b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 356b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 357b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 358b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 359b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler public static void removeUnnecessaryNonPersistentPreference(final Preference pref) { 360b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final String key = pref.getKey(); 361b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (pref.isPersistent() || key == null) { 362b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return; 363b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 364b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final SharedPreferences prefs = pref.getSharedPreferences(); 365b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (prefs != null && prefs.contains(key)) { 366b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler prefs.edit().remove(key).apply(); 367b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 368b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 369b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 370b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler @NonNull 371b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler public static String getSubtypeLocaleNameAsSentence(@Nullable InputMethodSubtype subtype, 372b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler @NonNull final Context context, @NonNull final InputMethodInfo inputMethodInfo) { 373b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (subtype == null) { 374b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return ""; 375b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 376b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Locale locale = getDisplayLocale(context); 377b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final CharSequence subtypeName = subtype.getDisplayName(context, 378b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() 379b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler .applicationInfo); 380b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return LocaleHelper.toSentenceCase(subtypeName.toString(), locale); 381b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 382b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 383b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler @NonNull 384b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler public static String getSubtypeLocaleNameListAsSentence( 385b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler @NonNull final List<InputMethodSubtype> subtypes, @NonNull final Context context, 386b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler @NonNull final InputMethodInfo inputMethodInfo) { 387b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (subtypes.isEmpty()) { 388b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return ""; 389b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 390b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Locale locale = getDisplayLocale(context); 391b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final int subtypeCount = subtypes.size(); 392b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final CharSequence[] subtypeNames = new CharSequence[subtypeCount]; 393b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler for (int i = 0; i < subtypeCount; i++) { 394b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler subtypeNames[i] = subtypes.get(i).getDisplayName(context, 395b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() 396b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler .applicationInfo); 397b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 398b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return LocaleHelper.toSentenceCase( 399b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler ListFormatter.getInstance(locale).format(subtypeNames), locale); 400b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 401b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler 402b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler @NonNull 403b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler private static Locale getDisplayLocale(@Nullable final Context context) { 404b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (context == null) { 405b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return Locale.getDefault(); 406b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 407b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (context.getResources() == null) { 408b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return Locale.getDefault(); 409b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 410b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Configuration configuration = context.getResources().getConfiguration(); 411b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (configuration == null) { 412b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return Locale.getDefault(); 413b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 414b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler final Locale configurationLocale = configuration.getLocales().get(0); 415b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler if (configurationLocale == null) { 416b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return Locale.getDefault(); 417b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 418b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler return configurationLocale; 419b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler } 420b8592357c37e681ba709b524a7202b7787f35e5aTony Mantler} 421