Merge "Move InputMethodAndSubtypeEnabler to SettingsLib and port to TV"
This commit is contained in:
committed by
Android (Google) Code Review
commit
cb0993ff94
@@ -3894,12 +3894,6 @@
|
|||||||
<string name="input_method_settings">Settings</string>
|
<string name="input_method_settings">Settings</string>
|
||||||
<!-- Spoken description for IME settings image button [CHAR LIMIT=NONE] -->
|
<!-- Spoken description for IME settings image button [CHAR LIMIT=NONE] -->
|
||||||
<string name="input_method_settings_button">Settings</string>
|
<string name="input_method_settings_button">Settings</string>
|
||||||
<!-- Title for settings of active input methods in each IME [CHAR LIMIT=35] -->
|
|
||||||
<string name="active_input_method_subtypes">Active input methods</string>
|
|
||||||
<!-- Title for settings whether or not the framework will select input methods in an IME based
|
|
||||||
on the current system locales. (The user can select multiple system locales)
|
|
||||||
[CHAR LIMIT=35] -->
|
|
||||||
<string name="use_system_language_to_select_input_method_subtypes">Use system languages</string>
|
|
||||||
<!-- Input Methods Settings localized format string for generating the appropriate "Foo settings" menu label for the Input Method named "Foo" [CHAR LIMIT=35] -->
|
<!-- Input Methods Settings localized format string for generating the appropriate "Foo settings" menu label for the Input Method named "Foo" [CHAR LIMIT=35] -->
|
||||||
<string name="input_methods_settings_label_format"><xliff:g id="ime_name">%1$s</xliff:g> settings</string>
|
<string name="input_methods_settings_label_format"><xliff:g id="ime_name">%1$s</xliff:g> settings</string>
|
||||||
<!-- Title for the settings of selecting active input methods of an IME [CHAR LIMIT=35] -->
|
<!-- Title for the settings of selecting active input methods of an IME [CHAR LIMIT=35] -->
|
||||||
|
@@ -42,6 +42,8 @@ import com.android.settings.SettingsPreferenceFragment;
|
|||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.search.Indexable;
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settings.search.SearchIndexableRaw;
|
import com.android.settings.search.SearchIndexableRaw;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper;
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@@ -16,42 +16,17 @@
|
|||||||
|
|
||||||
package com.android.settings.inputmethod;
|
package com.android.settings.inputmethod;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Bundle;
|
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.PreferenceScreen;
|
||||||
import android.support.v7.preference.TwoStatePreference;
|
|
||||||
import android.text.TextUtils;
|
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.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodAndSubtypeEnablerManager;
|
||||||
|
|
||||||
import java.text.Collator;
|
public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment {
|
||||||
import java.util.ArrayList;
|
private InputMethodAndSubtypeEnablerManager mManager;
|
||||||
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<String, List<Preference>> mInputMethodAndSubtypePrefsMap =
|
|
||||||
new HashMap<>();
|
|
||||||
private final HashMap<String, TwoStatePreference> mAutoSelectionPrefsMap = new HashMap<>();
|
|
||||||
private InputMethodManager mImm;
|
|
||||||
// TODO: Change mInputMethodInfoList to Map
|
|
||||||
private List<InputMethodInfo> mInputMethodInfoList;
|
|
||||||
private Collator mCollator;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -61,9 +36,6 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(final Bundle icicle) {
|
public void onCreate(final Bundle icicle) {
|
||||||
super.onCreate(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
|
// Input method id should be available from an Intent when this preference is launched as a
|
||||||
// single Activity (see InputMethodAndSubtypeEnablerActivity). It should be available
|
// single Activity (see InputMethodAndSubtypeEnablerActivity). It should be available
|
||||||
@@ -72,18 +44,10 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment
|
|||||||
final String targetImi = getStringExtraFromIntentOrArguments(
|
final String targetImi = getStringExtraFromIntentOrArguments(
|
||||||
android.provider.Settings.EXTRA_INPUT_METHOD_ID);
|
android.provider.Settings.EXTRA_INPUT_METHOD_ID);
|
||||||
|
|
||||||
mInputMethodInfoList = mImm.getInputMethodList();
|
final PreferenceScreen root =
|
||||||
mCollator = Collator.getInstance();
|
getPreferenceManager().createPreferenceScreen(getPrefContext());
|
||||||
|
mManager = new InputMethodAndSubtypeEnablerManager(this);
|
||||||
final PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
|
mManager.init(this, targetImi, root);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setPreferenceScreen(root);
|
setPreferenceScreen(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,202 +73,12 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
// Refresh internal states in mInputMethodSettingValues to keep the latest
|
mManager.refresh(getContext(), this);
|
||||||
// "InputMethodInfo"s and "InputMethodSubtype"s
|
|
||||||
InputMethodSettingValuesWrapper
|
|
||||||
.getInstance(getActivity()).refreshAllInputMethodAndSubtypes();
|
|
||||||
InputMethodAndSubtypeUtil.loadInputMethodSubtypeList(
|
|
||||||
this, getContentResolver(), mInputMethodInfoList, mInputMethodAndSubtypePrefsMap);
|
|
||||||
updateAutoSelectionPreferences();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(this, getContentResolver(),
|
mManager.save(getContext(), this);
|
||||||
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<Preference> 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<Preference>() {
|
|
||||||
@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<Preference> 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<Preference> 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<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId);
|
|
||||||
final List<InputMethodSubtype> 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 */);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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<String, HashSet<String>> imeToSubtypesMap) {
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
for (final String imi : imeToSubtypesMap.keySet()) {
|
|
||||||
if (builder.length() > 0) {
|
|
||||||
builder.append(INPUT_METHOD_SEPARATER);
|
|
||||||
}
|
|
||||||
final HashSet<String> 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<String> 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<String, HashSet<String>> 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<String, HashSet<String>> parseInputMethodsAndSubtypesString(
|
|
||||||
final String inputMethodsAndSubtypesString) {
|
|
||||||
final HashMap<String, HashSet<String>> 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<String> 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<String> enabledSubtypeIdSet) {
|
|
||||||
final HashMap<String, HashSet<String>> 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<String> getDisabledSystemIMEs(ContentResolver resolver) {
|
|
||||||
HashSet<String> 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<InputMethodInfo> inputMethodInfos,
|
|
||||||
boolean hasHardKeyboard) {
|
|
||||||
String currentInputMethodId = Settings.Secure.getString(resolver,
|
|
||||||
Settings.Secure.DEFAULT_INPUT_METHOD);
|
|
||||||
final int selectedInputMethodSubtype = getInputMethodSubtypeSelected(resolver);
|
|
||||||
final HashMap<String, HashSet<String>> enabledIMEsAndSubtypesMap =
|
|
||||||
getEnabledInputMethodsAndSubtypeList(resolver);
|
|
||||||
final HashSet<String> 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,
|
|
||||||
// <code>pref</code> 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<String>());
|
|
||||||
}
|
|
||||||
final HashSet<String> 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 <code>subtypePref.isEnabled()</code> 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 <code>subtypePref.isEnabled()</code> 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<InputMethodInfo> inputMethodInfos,
|
|
||||||
final Map<String, List<Preference>> inputMethodPrefsMap) {
|
|
||||||
final HashMap<String, HashSet<String>> 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<InputMethodInfo> 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<InputMethodInfo> inputMethodProperties,
|
|
||||||
final HashMap<String, HashSet<String>> 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<String> 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<InputMethodSubtype> 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;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -16,13 +16,14 @@
|
|||||||
|
|
||||||
package com.android.settings.inputmethod;
|
package com.android.settings.inputmethod;
|
||||||
|
|
||||||
|
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.support.v14.preference.SwitchPreference;
|
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
|
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
|
||||||
import android.support.v7.preference.Preference.OnPreferenceClickListener;
|
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.settings.R;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper;
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input method preference.
|
* Input method preference.
|
||||||
*
|
*
|
||||||
|
@@ -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<InputMethodInfo> mMethodList = new ArrayList<>();
|
|
||||||
private final HashMap<String, InputMethodInfo> mMethodMap = new HashMap<>();
|
|
||||||
private final InputMethodSettings mSettings;
|
|
||||||
private final InputMethodManager mImm;
|
|
||||||
private final HashSet<InputMethodInfo> 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<InputMethodInfo> 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<InputMethodInfo> 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<InputMethodInfo> 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<InputMethodInfo> 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<InputMethodInfo> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -52,6 +52,7 @@ import com.android.settings.SettingsPreferenceFragment;
|
|||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.search.Indexable;
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settings.search.SearchIndexableRaw;
|
import com.android.settings.search.SearchIndexableRaw;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@@ -24,6 +24,7 @@ import android.view.textservice.TextServicesManager;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.PreferenceController;
|
import com.android.settings.core.PreferenceController;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
|
||||||
|
|
||||||
public class SpellCheckerPreferenceController extends PreferenceController {
|
public class SpellCheckerPreferenceController extends PreferenceController {
|
||||||
|
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -26,7 +26,6 @@ import android.os.Bundle;
|
|||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
import android.view.inputmethod.InputMethodInfo;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.util.Preconditions;
|
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.BaseSearchIndexProvider;
|
||||||
import com.android.settings.search.Indexable;
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settings.search.SearchIndexableRaw;
|
import com.android.settings.search.SearchIndexableRaw;
|
||||||
|
import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
Reference in New Issue
Block a user