From 4d27b2ce5bea7d29f81cf30104b4e176c066fc72 Mon Sep 17 00:00:00 2001 From: Tony Mantler Date: Fri, 17 Feb 2017 14:04:40 -0800 Subject: [PATCH] Move InputMethodAndSubtypeEnabler to SettingsLib and port to TV Bug: 35315463 Test: adb shell am start -a android.settings.INPUT_METHOD_SUBTYPE_SETTINGS Change-Id: I17e6e64ff2c01577d4036bccafe7d0b4ad1d5ca5 --- res/values/strings.xml | 6 - .../AvailableVirtualKeyboardFragment.java | 2 + .../InputMethodAndSubtypeEnabler.java | 244 +--------- .../InputMethodAndSubtypeUtil.java | 431 ------------------ .../inputmethod/InputMethodPreference.java | 7 +- .../InputMethodSettingValuesWrapper.java | 203 --------- .../InputMethodSubtypePreference.java | 90 ---- .../inputmethod/PhysicalKeyboardFragment.java | 1 + .../SpellCheckerPreferenceController.java | 1 + .../SwitchWithNoTextPreference.java | 30 -- .../inputmethod/VirtualKeyboardFragment.java | 2 +- 11 files changed, 18 insertions(+), 999 deletions(-) delete mode 100644 src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java delete mode 100644 src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java delete mode 100644 src/com/android/settings/inputmethod/InputMethodSubtypePreference.java delete mode 100644 src/com/android/settings/inputmethod/SwitchWithNoTextPreference.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 852e81d94f1..f97e67b4988 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3892,12 +3892,6 @@ Settings Settings - - Active input methods - - Use system languages %1$s settings diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java index b9c07962587..a6df7a30dee 100644 --- a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java @@ -42,6 +42,8 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; +import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper; import java.text.Collator; import java.util.ArrayList; diff --git a/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java b/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java index a47daa15ca5..5fcaccfbd82 100644 --- a/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java +++ b/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java @@ -16,42 +16,17 @@ package com.android.settings.inputmethod; -import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Configuration; import android.os.Bundle; -import android.support.v7.preference.Preference; -import android.support.v7.preference.Preference.OnPreferenceChangeListener; -import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceScreen; -import android.support.v7.preference.TwoStatePreference; import android.text.TextUtils; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeEnablerManager; -import java.text.Collator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; - -public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment - implements OnPreferenceChangeListener { - private boolean mHaveHardKeyboard; - private final HashMap> mInputMethodAndSubtypePrefsMap = - new HashMap<>(); - private final HashMap mAutoSelectionPrefsMap = new HashMap<>(); - private InputMethodManager mImm; - // TODO: Change mInputMethodInfoList to Map - private List mInputMethodInfoList; - private Collator mCollator; +public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment { + private InputMethodAndSubtypeEnablerManager mManager; @Override public int getMetricsCategory() { @@ -61,9 +36,6 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment @Override public void onCreate(final Bundle icicle) { super.onCreate(icicle); - mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - final Configuration config = getResources().getConfiguration(); - mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); // Input method id should be available from an Intent when this preference is launched as a // single Activity (see InputMethodAndSubtypeEnablerActivity). It should be available @@ -72,18 +44,10 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment final String targetImi = getStringExtraFromIntentOrArguments( android.provider.Settings.EXTRA_INPUT_METHOD_ID); - mInputMethodInfoList = mImm.getInputMethodList(); - mCollator = Collator.getInstance(); - - final PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity()); - final int imiCount = mInputMethodInfoList.size(); - for (int index = 0; index < imiCount; ++index) { - final InputMethodInfo imi = mInputMethodInfoList.get(index); - // Add subtype preferences of this IME when it is specified or no IME is specified. - if (imi.getId().equals(targetImi) || TextUtils.isEmpty(targetImi)) { - addInputMethodSubtypePreferences(imi, root); - } - } + final PreferenceScreen root = + getPreferenceManager().createPreferenceScreen(getPrefContext()); + mManager = new InputMethodAndSubtypeEnablerManager(this); + mManager.init(this, targetImi, root); setPreferenceScreen(root); } @@ -109,202 +73,12 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment @Override public void onResume() { super.onResume(); - // Refresh internal states in mInputMethodSettingValues to keep the latest - // "InputMethodInfo"s and "InputMethodSubtype"s - InputMethodSettingValuesWrapper - .getInstance(getActivity()).refreshAllInputMethodAndSubtypes(); - InputMethodAndSubtypeUtil.loadInputMethodSubtypeList( - this, getContentResolver(), mInputMethodInfoList, mInputMethodAndSubtypePrefsMap); - updateAutoSelectionPreferences(); + mManager.refresh(getContext(), this); } @Override public void onPause() { super.onPause(); - InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(this, getContentResolver(), - mInputMethodInfoList, mHaveHardKeyboard); - } - - @Override - public boolean onPreferenceChange(final Preference pref, final Object newValue) { - if (!(newValue instanceof Boolean)) { - return true; // Invoke default behavior. - } - final boolean isChecking = (Boolean) newValue; - for (final String imiId : mAutoSelectionPrefsMap.keySet()) { - // An auto select subtype preference is changing. - if (mAutoSelectionPrefsMap.get(imiId) == pref) { - final TwoStatePreference autoSelectionPref = (TwoStatePreference) pref; - autoSelectionPref.setChecked(isChecking); - // Enable or disable subtypes depending on the auto selection preference. - setAutoSelectionSubtypesEnabled(imiId, autoSelectionPref.isChecked()); - return false; - } - } - // A subtype preference is changing. - if (pref instanceof InputMethodSubtypePreference) { - final InputMethodSubtypePreference subtypePref = (InputMethodSubtypePreference) pref; - subtypePref.setChecked(isChecking); - if (!subtypePref.isChecked()) { - // It takes care of the case where no subtypes are explicitly enabled then the auto - // selection preference is going to be checked. - updateAutoSelectionPreferences(); - } - return false; - } - return true; // Invoke default behavior. - } - - private void addInputMethodSubtypePreferences(final InputMethodInfo imi, - final PreferenceScreen root) { - final Context context = getPrefContext(); - final int subtypeCount = imi.getSubtypeCount(); - if (subtypeCount <= 1) { - return; - } - final String imiId = imi.getId(); - final PreferenceCategory keyboardSettingsCategory = - new PreferenceCategory(getPrefContext()); - root.addPreference(keyboardSettingsCategory); - final PackageManager pm = getPackageManager(); - final CharSequence label = imi.loadLabel(pm); - - keyboardSettingsCategory.setTitle(label); - keyboardSettingsCategory.setKey(imiId); - // TODO: Use toggle Preference if images are ready. - final TwoStatePreference autoSelectionPref = - new SwitchWithNoTextPreference(getPrefContext()); - mAutoSelectionPrefsMap.put(imiId, autoSelectionPref); - keyboardSettingsCategory.addPreference(autoSelectionPref); - autoSelectionPref.setOnPreferenceChangeListener(this); - - final PreferenceCategory activeInputMethodsCategory = - new PreferenceCategory(getPrefContext()); - activeInputMethodsCategory.setTitle(R.string.active_input_method_subtypes); - root.addPreference(activeInputMethodsCategory); - - CharSequence autoSubtypeLabel = null; - final ArrayList subtypePreferences = new ArrayList<>(); - for (int index = 0; index < subtypeCount; ++index) { - final InputMethodSubtype subtype = imi.getSubtypeAt(index); - if (subtype.overridesImplicitlyEnabledSubtype()) { - if (autoSubtypeLabel == null) { - autoSubtypeLabel = InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence( - subtype, context, imi); - } - } else { - final Preference subtypePref = new InputMethodSubtypePreference( - context, subtype, imi); - subtypePreferences.add(subtypePref); - } - } - Collections.sort(subtypePreferences, new Comparator() { - @Override - public int compare(final Preference lhs, final Preference rhs) { - if (lhs instanceof InputMethodSubtypePreference) { - return ((InputMethodSubtypePreference) lhs).compareTo(rhs, mCollator); - } - return lhs.compareTo(rhs); - } - }); - final int prefCount = subtypePreferences.size(); - for (int index = 0; index < prefCount; ++index) { - final Preference pref = subtypePreferences.get(index); - activeInputMethodsCategory.addPreference(pref); - pref.setOnPreferenceChangeListener(this); - InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref); - } - mInputMethodAndSubtypePrefsMap.put(imiId, subtypePreferences); - if (TextUtils.isEmpty(autoSubtypeLabel)) { - autoSelectionPref.setTitle( - R.string.use_system_language_to_select_input_method_subtypes); - } else { - autoSelectionPref.setTitle(autoSubtypeLabel); - } - } - - private boolean isNoSubtypesExplicitlySelected(final String imiId) { - final List subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); - for (final Preference pref : subtypePrefs) { - if (pref instanceof TwoStatePreference && ((TwoStatePreference)pref).isChecked()) { - return false; - } - } - return true; - } - - private void setAutoSelectionSubtypesEnabled(final String imiId, - final boolean autoSelectionEnabled) { - final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId); - if (autoSelectionPref == null) { - return; - } - autoSelectionPref.setChecked(autoSelectionEnabled); - final List subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); - for (final Preference pref : subtypePrefs) { - if (pref instanceof TwoStatePreference) { - // When autoSelectionEnabled is true, all subtype prefs need to be disabled with - // implicitly checked subtypes. In case of false, all subtype prefs need to be - // enabled. - pref.setEnabled(!autoSelectionEnabled); - if (autoSelectionEnabled) { - ((TwoStatePreference)pref).setChecked(false); - } - } - } - if (autoSelectionEnabled) { - InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( - this, getContentResolver(), mInputMethodInfoList, mHaveHardKeyboard); - updateImplicitlyEnabledSubtypes(imiId, true /* check */); - } - } - - private void updateImplicitlyEnabledSubtypes(final String targetImiId, final boolean check) { - // When targetImiId is null, apply to all subtypes of all IMEs - for (final InputMethodInfo imi : mInputMethodInfoList) { - final String imiId = imi.getId(); - final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId); - // No need to update implicitly enabled subtypes when the user has unchecked the - // "subtype auto selection". - if (autoSelectionPref == null || !autoSelectionPref.isChecked()) { - continue; - } - if (imiId.equals(targetImiId) || targetImiId == null) { - updateImplicitlyEnabledSubtypesOf(imi, check); - } - } - } - - private void updateImplicitlyEnabledSubtypesOf(final InputMethodInfo imi, final boolean check) { - final String imiId = imi.getId(); - final List subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); - final List implicitlyEnabledSubtypes = - mImm.getEnabledInputMethodSubtypeList(imi, true); - if (subtypePrefs == null || implicitlyEnabledSubtypes == null) { - return; - } - for (final Preference pref : subtypePrefs) { - if (!(pref instanceof TwoStatePreference)) { - continue; - } - final TwoStatePreference subtypePref = (TwoStatePreference)pref; - subtypePref.setChecked(false); - if (check) { - for (final InputMethodSubtype subtype : implicitlyEnabledSubtypes) { - final String implicitlyEnabledSubtypePrefKey = imiId + subtype.hashCode(); - if (subtypePref.getKey().equals(implicitlyEnabledSubtypePrefKey)) { - subtypePref.setChecked(true); - break; - } - } - } - } - } - - private void updateAutoSelectionPreferences() { - for (final String imiId : mInputMethodAndSubtypePrefsMap.keySet()) { - setAutoSelectionSubtypesEnabled(imiId, isNoSubtypesExplicitlySelected(imiId)); - } - updateImplicitlyEnabledSubtypes(null /* targetImiId */, true /* check */); + mManager.save(getContext(), this); } } diff --git a/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java b/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java deleted file mode 100644 index 3d8d5730642..00000000000 --- a/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.inputmethod; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ContentResolver; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.icu.text.ListFormatter; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; -import android.support.v7.preference.TwoStatePreference; -import android.text.TextUtils; -import android.util.Log; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.internal.app.LocaleHelper; -import com.android.internal.inputmethod.InputMethodUtils; -import com.android.settings.SettingsPreferenceFragment; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -// TODO: Consolidate this with {@link InputMethodSettingValuesWrapper}. -class InputMethodAndSubtypeUtil { - - private static final boolean DEBUG = false; - static final String TAG = "InputMethdAndSubtypeUtil"; - - private static final char INPUT_METHOD_SEPARATER = ':'; - private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';'; - private static final int NOT_A_SUBTYPE_ID = -1; - - private static final TextUtils.SimpleStringSplitter sStringInputMethodSplitter - = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER); - - private static final TextUtils.SimpleStringSplitter sStringInputMethodSubtypeSplitter - = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER); - - // InputMethods and subtypes are saved in the settings as follows: - // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1 - static String buildInputMethodsAndSubtypesString( - final HashMap> imeToSubtypesMap) { - final StringBuilder builder = new StringBuilder(); - for (final String imi : imeToSubtypesMap.keySet()) { - if (builder.length() > 0) { - builder.append(INPUT_METHOD_SEPARATER); - } - final HashSet subtypeIdSet = imeToSubtypesMap.get(imi); - builder.append(imi); - for (final String subtypeId : subtypeIdSet) { - builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId); - } - } - return builder.toString(); - } - - private static String buildInputMethodsString(final HashSet imiList) { - final StringBuilder builder = new StringBuilder(); - for (final String imi : imiList) { - if (builder.length() > 0) { - builder.append(INPUT_METHOD_SEPARATER); - } - builder.append(imi); - } - return builder.toString(); - } - - private static int getInputMethodSubtypeSelected(ContentResolver resolver) { - try { - return Settings.Secure.getInt(resolver, - Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE); - } catch (SettingNotFoundException e) { - return NOT_A_SUBTYPE_ID; - } - } - - private static boolean isInputMethodSubtypeSelected(ContentResolver resolver) { - return getInputMethodSubtypeSelected(resolver) != NOT_A_SUBTYPE_ID; - } - - private static void putSelectedInputMethodSubtype(ContentResolver resolver, int hashCode) { - Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, hashCode); - } - - // Needs to modify InputMethodManageService if you want to change the format of saved string. - private static HashMap> getEnabledInputMethodsAndSubtypeList( - ContentResolver resolver) { - final String enabledInputMethodsStr = Settings.Secure.getString( - resolver, Settings.Secure.ENABLED_INPUT_METHODS); - if (DEBUG) { - Log.d(TAG, "--- Load enabled input methods: " + enabledInputMethodsStr); - } - return parseInputMethodsAndSubtypesString(enabledInputMethodsStr); - } - - static HashMap> parseInputMethodsAndSubtypesString( - final String inputMethodsAndSubtypesString) { - final HashMap> subtypesMap = new HashMap<>(); - if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) { - return subtypesMap; - } - sStringInputMethodSplitter.setString(inputMethodsAndSubtypesString); - while (sStringInputMethodSplitter.hasNext()) { - final String nextImsStr = sStringInputMethodSplitter.next(); - sStringInputMethodSubtypeSplitter.setString(nextImsStr); - if (sStringInputMethodSubtypeSplitter.hasNext()) { - final HashSet subtypeIdSet = new HashSet<>(); - // The first element is {@link InputMethodInfoId}. - final String imiId = sStringInputMethodSubtypeSplitter.next(); - while (sStringInputMethodSubtypeSplitter.hasNext()) { - subtypeIdSet.add(sStringInputMethodSubtypeSplitter.next()); - } - subtypesMap.put(imiId, subtypeIdSet); - } - } - return subtypesMap; - } - - static void enableInputMethodSubtypesOf(final ContentResolver resolver, final String imiId, - final HashSet enabledSubtypeIdSet) { - final HashMap> enabledImeAndSubtypeIdsMap = - getEnabledInputMethodsAndSubtypeList(resolver); - enabledImeAndSubtypeIdsMap.put(imiId, enabledSubtypeIdSet); - final String enabledImesAndSubtypesString = buildInputMethodsAndSubtypesString( - enabledImeAndSubtypeIdsMap); - Settings.Secure.putString(resolver, - Settings.Secure.ENABLED_INPUT_METHODS, enabledImesAndSubtypesString); - } - - private static HashSet getDisabledSystemIMEs(ContentResolver resolver) { - HashSet set = new HashSet<>(); - String disabledIMEsStr = Settings.Secure.getString( - resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS); - if (TextUtils.isEmpty(disabledIMEsStr)) { - return set; - } - sStringInputMethodSplitter.setString(disabledIMEsStr); - while(sStringInputMethodSplitter.hasNext()) { - set.add(sStringInputMethodSplitter.next()); - } - return set; - } - - static void saveInputMethodSubtypeList(SettingsPreferenceFragment context, - ContentResolver resolver, List inputMethodInfos, - boolean hasHardKeyboard) { - String currentInputMethodId = Settings.Secure.getString(resolver, - Settings.Secure.DEFAULT_INPUT_METHOD); - final int selectedInputMethodSubtype = getInputMethodSubtypeSelected(resolver); - final HashMap> enabledIMEsAndSubtypesMap = - getEnabledInputMethodsAndSubtypeList(resolver); - final HashSet disabledSystemIMEs = getDisabledSystemIMEs(resolver); - - boolean needsToResetSelectedSubtype = false; - for (final InputMethodInfo imi : inputMethodInfos) { - final String imiId = imi.getId(); - final Preference pref = context.findPreference(imiId); - if (pref == null) { - continue; - } - // In the choose input method screen or in the subtype enabler screen, - // pref is an instance of TwoStatePreference. - final boolean isImeChecked = (pref instanceof TwoStatePreference) ? - ((TwoStatePreference) pref).isChecked() - : enabledIMEsAndSubtypesMap.containsKey(imiId); - final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId); - final boolean systemIme = InputMethodUtils.isSystemIme(imi); - if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance( - context.getActivity()).isAlwaysCheckedIme(imi, context.getActivity())) - || isImeChecked) { - if (!enabledIMEsAndSubtypesMap.containsKey(imiId)) { - // imiId has just been enabled - enabledIMEsAndSubtypesMap.put(imiId, new HashSet()); - } - final HashSet subtypesSet = enabledIMEsAndSubtypesMap.get(imiId); - - boolean subtypePrefFound = false; - final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - final InputMethodSubtype subtype = imi.getSubtypeAt(i); - final String subtypeHashCodeStr = String.valueOf(subtype.hashCode()); - final TwoStatePreference subtypePref = (TwoStatePreference) context - .findPreference(imiId + subtypeHashCodeStr); - // In the Configure input method screen which does not have subtype preferences. - if (subtypePref == null) { - continue; - } - if (!subtypePrefFound) { - // Once subtype preference is found, subtypeSet needs to be cleared. - // Because of system change, hashCode value could have been changed. - subtypesSet.clear(); - // If selected subtype preference is disabled, needs to reset. - needsToResetSelectedSubtype = true; - subtypePrefFound = true; - } - // Checking subtypePref.isEnabled() is insufficient to determine - // whether the user manually enabled this subtype or not. Implicitly-enabled - // subtypes are also checked just as an indicator to users. We also need to - // check subtypePref.isEnabled() so that only manually enabled - // subtypes can be saved here. - if (subtypePref.isEnabled() && subtypePref.isChecked()) { - subtypesSet.add(subtypeHashCodeStr); - if (isCurrentInputMethod) { - if (selectedInputMethodSubtype == subtype.hashCode()) { - // Selected subtype is still enabled, there is no need to reset - // selected subtype. - needsToResetSelectedSubtype = false; - } - } - } else { - subtypesSet.remove(subtypeHashCodeStr); - } - } - } else { - enabledIMEsAndSubtypesMap.remove(imiId); - if (isCurrentInputMethod) { - // We are processing the current input method, but found that it's not enabled. - // This means that the current input method has been uninstalled. - // If currentInputMethod is already uninstalled, InputMethodManagerService will - // find the applicable IME from the history and the system locale. - if (DEBUG) { - Log.d(TAG, "Current IME was uninstalled or disabled."); - } - currentInputMethodId = null; - } - } - // If it's a disabled system ime, add it to the disabled list so that it - // doesn't get enabled automatically on any changes to the package list - if (systemIme && hasHardKeyboard) { - if (disabledSystemIMEs.contains(imiId)) { - if (isImeChecked) { - disabledSystemIMEs.remove(imiId); - } - } else { - if (!isImeChecked) { - disabledSystemIMEs.add(imiId); - } - } - } - } - - final String enabledIMEsAndSubtypesString = buildInputMethodsAndSubtypesString( - enabledIMEsAndSubtypesMap); - final String disabledSystemIMEsString = buildInputMethodsString(disabledSystemIMEs); - if (DEBUG) { - Log.d(TAG, "--- Save enabled inputmethod settings. :" + enabledIMEsAndSubtypesString); - Log.d(TAG, "--- Save disabled system inputmethod settings. :" - + disabledSystemIMEsString); - Log.d(TAG, "--- Save default inputmethod settings. :" + currentInputMethodId); - Log.d(TAG, "--- Needs to reset the selected subtype :" + needsToResetSelectedSubtype); - Log.d(TAG, "--- Subtype is selected :" + isInputMethodSubtypeSelected(resolver)); - } - - // Redefines SelectedSubtype when all subtypes are unchecked or there is no subtype - // selected. And if the selected subtype of the current input method was disabled, - // We should reset the selected input method's subtype. - if (needsToResetSelectedSubtype || !isInputMethodSubtypeSelected(resolver)) { - if (DEBUG) { - Log.d(TAG, "--- Reset inputmethod subtype because it's not defined."); - } - putSelectedInputMethodSubtype(resolver, NOT_A_SUBTYPE_ID); - } - - Settings.Secure.putString(resolver, - Settings.Secure.ENABLED_INPUT_METHODS, enabledIMEsAndSubtypesString); - if (disabledSystemIMEsString.length() > 0) { - Settings.Secure.putString(resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, - disabledSystemIMEsString); - } - // If the current input method is unset, InputMethodManagerService will find the applicable - // IME from the history and the system locale. - Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, - currentInputMethodId != null ? currentInputMethodId : ""); - } - - static void loadInputMethodSubtypeList(final SettingsPreferenceFragment context, - final ContentResolver resolver, final List inputMethodInfos, - final Map> inputMethodPrefsMap) { - final HashMap> enabledSubtypes = - getEnabledInputMethodsAndSubtypeList(resolver); - - for (final InputMethodInfo imi : inputMethodInfos) { - final String imiId = imi.getId(); - final Preference pref = context.findPreference(imiId); - if (pref instanceof TwoStatePreference) { - final TwoStatePreference subtypePref = (TwoStatePreference) pref; - final boolean isEnabled = enabledSubtypes.containsKey(imiId); - subtypePref.setChecked(isEnabled); - if (inputMethodPrefsMap != null) { - for (final Preference childPref: inputMethodPrefsMap.get(imiId)) { - childPref.setEnabled(isEnabled); - } - } - setSubtypesPreferenceEnabled(context, inputMethodInfos, imiId, isEnabled); - } - } - updateSubtypesPreferenceChecked(context, inputMethodInfos, enabledSubtypes); - } - - static void setSubtypesPreferenceEnabled(final SettingsPreferenceFragment context, - final List inputMethodProperties, final String id, - final boolean enabled) { - final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); - for (final InputMethodInfo imi : inputMethodProperties) { - if (id.equals(imi.getId())) { - final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - final InputMethodSubtype subtype = imi.getSubtypeAt(i); - final TwoStatePreference pref = (TwoStatePreference) preferenceScreen - .findPreference(id + subtype.hashCode()); - if (pref != null) { - pref.setEnabled(enabled); - } - } - } - } - } - - private static void updateSubtypesPreferenceChecked(final SettingsPreferenceFragment context, - final List inputMethodProperties, - final HashMap> enabledSubtypes) { - final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); - for (final InputMethodInfo imi : inputMethodProperties) { - final String id = imi.getId(); - if (!enabledSubtypes.containsKey(id)) { - // There is no need to enable/disable subtypes of disabled IMEs. - continue; - } - final HashSet enabledSubtypesSet = enabledSubtypes.get(id); - final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - final InputMethodSubtype subtype = imi.getSubtypeAt(i); - final String hashCode = String.valueOf(subtype.hashCode()); - if (DEBUG) { - Log.d(TAG, "--- Set checked state: " + "id" + ", " + hashCode + ", " - + enabledSubtypesSet.contains(hashCode)); - } - final TwoStatePreference pref = (TwoStatePreference) preferenceScreen - .findPreference(id + hashCode); - if (pref != null) { - pref.setChecked(enabledSubtypesSet.contains(hashCode)); - } - } - } - } - - static void removeUnnecessaryNonPersistentPreference(final Preference pref) { - final String key = pref.getKey(); - if (pref.isPersistent() || key == null) { - return; - } - final SharedPreferences prefs = pref.getSharedPreferences(); - if (prefs != null && prefs.contains(key)) { - prefs.edit().remove(key).apply(); - } - } - - @NonNull - static String getSubtypeLocaleNameAsSentence(@Nullable InputMethodSubtype subtype, - @NonNull final Context context, @NonNull final InputMethodInfo inputMethodInfo) { - if (subtype == null) { - return ""; - } - final Locale locale = getDisplayLocale(context); - final CharSequence subtypeName = subtype.getDisplayName(context, - inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() - .applicationInfo); - return LocaleHelper.toSentenceCase(subtypeName.toString(), locale); - } - - @NonNull - static String getSubtypeLocaleNameListAsSentence( - @NonNull final List subtypes, @NonNull final Context context, - @NonNull final InputMethodInfo inputMethodInfo) { - if (subtypes.isEmpty()) { - return ""; - } - final Locale locale = getDisplayLocale(context); - final int subtypeCount = subtypes.size(); - final CharSequence[] subtypeNames = new CharSequence[subtypeCount]; - for (int i = 0; i < subtypeCount; i++) { - subtypeNames[i] = subtypes.get(i).getDisplayName(context, - inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() - .applicationInfo); - } - return LocaleHelper.toSentenceCase( - ListFormatter.getInstance(locale).format(subtypeNames), locale); - } - - @NonNull - private static Locale getDisplayLocale(@Nullable final Context context) { - if (context == null) { - return Locale.getDefault(); - } - if (context.getResources() == null) { - return Locale.getDefault(); - } - final Configuration configuration = context.getResources().getConfiguration(); - if (configuration == null) { - return Locale.getDefault(); - } - final Locale configurationLocale = configuration.getLocales().get(0); - if (configurationLocale == null) { - return Locale.getDefault(); - } - return configurationLocale; - } -} diff --git a/src/com/android/settings/inputmethod/InputMethodPreference.java b/src/com/android/settings/inputmethod/InputMethodPreference.java index b2c28001a25..463a043cd6d 100755 --- a/src/com/android/settings/inputmethod/InputMethodPreference.java +++ b/src/com/android/settings/inputmethod/InputMethodPreference.java @@ -16,13 +16,14 @@ package com.android.settings.inputmethod; +import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.UserHandle; -import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.support.v7.preference.Preference.OnPreferenceClickListener; @@ -37,12 +38,12 @@ import com.android.internal.inputmethod.InputMethodUtils; import com.android.settings.R; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedSwitchPreference; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; +import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper; import java.text.Collator; import java.util.List; -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; - /** * Input method preference. * diff --git a/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java b/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java deleted file mode 100644 index cb2661995e8..00000000000 --- a/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.inputmethod; - -import android.app.ActivityManager; -import android.content.Context; -import android.os.RemoteException; -import android.util.Log; -import android.util.Slog; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.internal.inputmethod.InputMethodUtils; -import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; - -/** - * This class is a wrapper for InputMethodSettings. You need to refresh internal states - * manually on some events when "InputMethodInfo"s and "InputMethodSubtype"s can be - * changed. - */ -// TODO: Consolidate this with {@link InputMethodAndSubtypeUtil}. -class InputMethodSettingValuesWrapper { - private static final String TAG = InputMethodSettingValuesWrapper.class.getSimpleName(); - - private static volatile InputMethodSettingValuesWrapper sInstance; - private final ArrayList mMethodList = new ArrayList<>(); - private final HashMap mMethodMap = new HashMap<>(); - private final InputMethodSettings mSettings; - private final InputMethodManager mImm; - private final HashSet mAsciiCapableEnabledImis = new HashSet<>(); - - static InputMethodSettingValuesWrapper getInstance(Context context) { - if (sInstance == null) { - synchronized (TAG) { - if (sInstance == null) { - sInstance = new InputMethodSettingValuesWrapper(context); - } - } - } - return sInstance; - } - - private static int getDefaultCurrentUserId() { - try { - return ActivityManager.getService().getCurrentUser().id; - } catch (RemoteException e) { - Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e); - } - return 0; - } - - // Ensure singleton - private InputMethodSettingValuesWrapper(Context context) { - mSettings = new InputMethodSettings(context.getResources(), context.getContentResolver(), - mMethodMap, mMethodList, getDefaultCurrentUserId(), false /* copyOnWrite */); - mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - refreshAllInputMethodAndSubtypes(); - } - - void refreshAllInputMethodAndSubtypes() { - synchronized (mMethodMap) { - mMethodList.clear(); - mMethodMap.clear(); - final List imms = mImm.getInputMethodList(); - mMethodList.addAll(imms); - for (InputMethodInfo imi : imms) { - mMethodMap.put(imi.getId(), imi); - } - updateAsciiCapableEnabledImis(); - } - } - - // TODO: Add a cts to ensure at least one AsciiCapableSubtypeEnabledImis exist - private void updateAsciiCapableEnabledImis() { - synchronized (mMethodMap) { - mAsciiCapableEnabledImis.clear(); - final List enabledImis = mSettings.getEnabledInputMethodListLocked(); - for (final InputMethodInfo imi : enabledImis) { - final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - final InputMethodSubtype subtype = imi.getSubtypeAt(i); - if (InputMethodUtils.SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode()) - && subtype.isAsciiCapable()) { - mAsciiCapableEnabledImis.add(imi); - break; - } - } - } - } - } - - List getInputMethodList() { - synchronized (mMethodMap) { - return mMethodList; - } - } - - CharSequence getCurrentInputMethodName(Context context) { - synchronized (mMethodMap) { - final InputMethodInfo imi = mMethodMap.get(mSettings.getSelectedInputMethod()); - if (imi == null) { - Log.w(TAG, "Invalid selected imi: " + mSettings.getSelectedInputMethod()); - return ""; - } - final InputMethodSubtype subtype = mImm.getCurrentInputMethodSubtype(); - return InputMethodUtils.getImeAndSubtypeDisplayName(context, imi, subtype); - } - } - - boolean isAlwaysCheckedIme(InputMethodInfo imi, Context context) { - final boolean isEnabled = isEnabledImi(imi); - synchronized (mMethodMap) { - if (mSettings.getEnabledInputMethodListLocked().size() <= 1 && isEnabled) { - return true; - } - } - - final int enabledValidSystemNonAuxAsciiCapableImeCount = - getEnabledValidSystemNonAuxAsciiCapableImeCount(context); - if (enabledValidSystemNonAuxAsciiCapableImeCount > 1) { - return false; - } - - if (enabledValidSystemNonAuxAsciiCapableImeCount == 1 && !isEnabled) { - return false; - } - - if (!InputMethodUtils.isSystemIme(imi)) { - return false; - } - return isValidSystemNonAuxAsciiCapableIme(imi, context); - } - - private int getEnabledValidSystemNonAuxAsciiCapableImeCount(Context context) { - int count = 0; - final List enabledImis; - synchronized (mMethodMap) { - enabledImis = mSettings.getEnabledInputMethodListLocked(); - } - for (final InputMethodInfo imi : enabledImis) { - if (isValidSystemNonAuxAsciiCapableIme(imi, context)) { - ++count; - } - } - if (count == 0) { - Log.w(TAG, "No \"enabledValidSystemNonAuxAsciiCapableIme\"s found."); - } - return count; - } - - boolean isEnabledImi(InputMethodInfo imi) { - final List enabledImis; - synchronized (mMethodMap) { - enabledImis = mSettings.getEnabledInputMethodListLocked(); - } - for (final InputMethodInfo tempImi : enabledImis) { - if (tempImi.getId().equals(imi.getId())) { - return true; - } - } - return false; - } - - boolean isValidSystemNonAuxAsciiCapableIme(InputMethodInfo imi, Context context) { - if (imi.isAuxiliaryIme()) { - return false; - } - final Locale systemLocale = context.getResources().getConfiguration().locale; - if (InputMethodUtils.isSystemImeThatHasSubtypeOf(imi, context, - true /* checkDefaultAttribute */, systemLocale, false /* checkCountry */, - InputMethodUtils.SUBTYPE_MODE_ANY)) { - return true; - } - if (mAsciiCapableEnabledImis.isEmpty()) { - Log.w(TAG, "ascii capable subtype enabled imi not found. Fall back to English" - + " Keyboard subtype."); - return InputMethodUtils.containsSubtypeOf(imi, Locale.ENGLISH, false /* checkCountry */, - InputMethodUtils.SUBTYPE_MODE_KEYBOARD); - } - return mAsciiCapableEnabledImis.contains(imi); - } -} diff --git a/src/com/android/settings/inputmethod/InputMethodSubtypePreference.java b/src/com/android/settings/inputmethod/InputMethodSubtypePreference.java deleted file mode 100644 index 678b2d96aa5..00000000000 --- a/src/com/android/settings/inputmethod/InputMethodSubtypePreference.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.inputmethod; - -import android.content.Context; -import android.support.v7.preference.Preference; -import android.text.TextUtils; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.internal.inputmethod.InputMethodUtils; - -import java.text.Collator; -import java.util.Locale; - -/** - * Input method subtype preference. - * - * This preference represents a subtype of an IME. It is used to enable or disable the subtype. - */ -class InputMethodSubtypePreference extends SwitchWithNoTextPreference { - private final boolean mIsSystemLocale; - private final boolean mIsSystemLanguage; - - InputMethodSubtypePreference(final Context context, final InputMethodSubtype subtype, - final InputMethodInfo imi) { - super(context); - setPersistent(false); - setKey(imi.getId() + subtype.hashCode()); - final CharSequence subtypeLabel = - InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence(subtype, context, imi); - setTitle(subtypeLabel); - final String subtypeLocaleString = subtype.getLocale(); - if (TextUtils.isEmpty(subtypeLocaleString)) { - mIsSystemLocale = false; - mIsSystemLanguage = false; - } else { - final Locale systemLocale = context.getResources().getConfiguration().locale; - mIsSystemLocale = subtypeLocaleString.equals(systemLocale.toString()); - mIsSystemLanguage = mIsSystemLocale - || InputMethodUtils.getLanguageFromLocaleString(subtypeLocaleString) - .equals(systemLocale.getLanguage()); - } - } - - int compareTo(final Preference rhs, final Collator collator) { - if (this == rhs) { - return 0; - } - if (rhs instanceof InputMethodSubtypePreference) { - final InputMethodSubtypePreference rhsPref = (InputMethodSubtypePreference) rhs; - if (mIsSystemLocale && !rhsPref.mIsSystemLocale) { - return -1; - } - if (!mIsSystemLocale && rhsPref.mIsSystemLocale) { - return 1; - } - if (mIsSystemLanguage && !rhsPref.mIsSystemLanguage) { - return -1; - } - if (!mIsSystemLanguage && rhsPref.mIsSystemLanguage) { - return 1; - } - final CharSequence t0 = getTitle(); - final CharSequence t1 = rhs.getTitle(); - if (t0 == null && t1 == null) { - return Integer.compare(hashCode(), rhs.hashCode()); - } - if (t0 != null && t1 != null) { - return collator.compare(t0.toString(), t1.toString()); - } - return t0 == null ? -1 : 1; - } - return super.compareTo(rhs); - } -} diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java index 1ecb2502533..ad6e0417ff7 100644 --- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java @@ -52,6 +52,7 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; import java.text.Collator; import java.util.ArrayList; diff --git a/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java b/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java index 8fcaa74043f..5ab2cbae08c 100644 --- a/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java +++ b/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java @@ -24,6 +24,7 @@ import android.view.textservice.TextServicesManager; import com.android.settings.R; import com.android.settings.core.PreferenceController; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; public class SpellCheckerPreferenceController extends PreferenceController { diff --git a/src/com/android/settings/inputmethod/SwitchWithNoTextPreference.java b/src/com/android/settings/inputmethod/SwitchWithNoTextPreference.java deleted file mode 100644 index 727f56f4e54..00000000000 --- a/src/com/android/settings/inputmethod/SwitchWithNoTextPreference.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.inputmethod; - -import android.content.Context; -import android.support.v14.preference.SwitchPreference; - -class SwitchWithNoTextPreference extends SwitchPreference { - private static final String EMPTY_TEXT = ""; - - SwitchWithNoTextPreference(final Context context) { - super(context); - setSwitchTextOn(EMPTY_TEXT); - setSwitchTextOff(EMPTY_TEXT); - } -} diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java index da5cb04db1d..c3623894d51 100644 --- a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java @@ -26,7 +26,6 @@ import android.os.Bundle; import android.support.v7.preference.Preference; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.Preconditions; @@ -35,6 +34,7 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; import java.text.Collator; import java.util.ArrayList;