Reorganize language & input settings
Bug: 14860252
Bug: 16115751
Change-Id: I198aabebc08421764b78e137e7f26d2a7772d452
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d8c3171..b52f40d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3116,8 +3116,10 @@
<string name="input_methods_settings_title">Text input</string>
<!-- Setting name for Input Method chooser -->
<string name="input_method">Input method</string>
- <!-- Title for the option to press to choose the current input method [CHAR LIMIT=35] -->
- <string name="current_input_method">Default</string>
+ <!-- Title for the option to press to enable or disable keyboards, also known as input methods [CHAR LIMIT=35] -->
+ <string name="choose_input_methods">Choose Keyboards</string>
+ <!-- Title for the option to press to choose the current keyboard, also known as input method [CHAR LIMIT=35] -->
+ <string name="current_input_method">Current Keyboard</string>
<!-- Title for setting the visibility of input method selector [CHAR LIMIT=35] -->
<string name="input_method_selector">Input method selector</string>
<!-- An option to always show input method selector automatically when needed [CHAR LIMIT=25] -->
diff --git a/res/xml/language_settings.xml b/res/xml/language_settings.xml
index c210312..d8e7603 100644
--- a/res/xml/language_settings.xml
+++ b/res/xml/language_settings.xml
@@ -32,10 +32,17 @@
android:key="key_user_dictionary_settings"
android:title="@string/user_dict_settings_title" />
- <PreferenceCategory android:key="keyboard_settings_category"
+ <PreferenceCategory
+ android:key="keyboard_settings_category"
android:title="@string/keyboard_settings_category">
- <PreferenceScreen android:key="current_input_method"
+ <!-- An intent for this preference will be populated programmatically. -->
+ <PreferenceScreen
+ android:key="choose_input_methods"
+ android:title="@string/choose_input_methods" />
+ <PreferenceScreen
+ android:key="current_input_method"
android:title="@string/current_input_method" />
+ <!-- Enabled input method list will be populated programmatically here. -->
</PreferenceCategory>
<PreferenceCategory
diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
index 0f9ae19..073daa6 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
@@ -16,26 +16,15 @@
package com.android.settings.inputmethod;
-import android.content.ComponentName;
-import android.content.pm.ServiceInfo;
-import com.android.settings.R;
-import com.android.settings.Settings.KeyboardLayoutPickerActivity;
-import com.android.settings.Settings.SpellCheckersSettingsActivity;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.UserDictionarySettings;
-import com.android.settings.Utils;
-import com.android.settings.VoiceInputOutputSettings;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.search.Indexable;
-import com.android.settings.search.SearchIndexableRaw;
-
import android.app.Activity;
import android.app.Fragment;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -47,7 +36,6 @@
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
@@ -60,17 +48,33 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.BaseAdapter;
+import com.android.settings.R;
+import com.android.settings.Settings.KeyboardLayoutPickerActivity;
+import com.android.settings.Settings.SpellCheckersSettingsActivity;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.SubSettings;
+import com.android.settings.UserDictionarySettings;
+import com.android.settings.Utils;
+import com.android.settings.VoiceInputOutputSettings;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+
+import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener, InputManager.InputDeviceListener,
- KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable {
+ KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable,
+ InputMethodPreference.onSavePreferenceListener {
private static final String KEY_PHONE_LANGUAGE = "phone_language";
+ private static final String KEY_CHOOSE_INPUT_METHODS = "choose_input_methods";
private static final String KEY_CURRENT_INPUT_METHOD = "current_input_method";
private static final String KEY_INPUT_METHOD_SELECTOR = "input_method_selector";
private static final String KEY_USER_DICTIONARY_SETTINGS = "key_user_dictionary_settings";
@@ -95,37 +99,29 @@
private final ArrayList<PreferenceScreen> mHardKeyboardPreferenceList = new ArrayList<>();
private InputManager mIm;
private InputMethodManager mImm;
- private boolean mIsOnlyImeSettings;
+ private boolean mShowsOnlyFullImeAndKeyboardList;
private Handler mHandler;
private SettingsObserver mSettingsObserver;
private Intent mIntentWaitingForResult;
private InputMethodSettingValuesWrapper mInputMethodSettingValues;
- private final OnPreferenceChangeListener mOnImePreferenceChangedListener =
- new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference arg0, Object arg1) {
- InputMethodSettingValuesWrapper.getInstance(
- arg0.getContext()).refreshAllInputMethodAndSubtypes();
- ((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();
- updateInputMethodPreferenceViews();
- return true;
- }
- };
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.language_settings);
+ final Activity activity = getActivity();
+ mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(activity);
+
try {
mDefaultInputMethodSelectorVisibility = Integer.valueOf(
getString(R.string.input_method_selector_visibility_default_value));
} catch (NumberFormatException e) {
}
- if (getActivity().getAssets().getLocales().length == 1) {
+ if (activity.getAssets().getLocales().length == 1) {
// No "Select language" pref if there's only one system locale available.
getPreferenceScreen().removePreference(findPreference(KEY_PHONE_LANGUAGE));
} else {
@@ -149,45 +145,42 @@
"game_controller_settings_category");
// Filter out irrelevant features if invoked from IME settings button.
- mIsOnlyImeSettings = Settings.ACTION_INPUT_METHOD_SETTINGS.equals(
- getActivity().getIntent().getAction());
- getActivity().getIntent().setAction(null);
- if (mIsOnlyImeSettings) {
+ mShowsOnlyFullImeAndKeyboardList = Settings.ACTION_INPUT_METHOD_SETTINGS.equals(
+ activity.getIntent().getAction());
+ activity.getIntent().setAction(null);
+ if (mShowsOnlyFullImeAndKeyboardList) {
getPreferenceScreen().removeAll();
getPreferenceScreen().addPreference(mHardKeyboardCategory);
if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) {
getPreferenceScreen().addPreference(mShowInputMethodSelectorPref);
}
+ mKeyboardSettingsCategory.removeAll();
getPreferenceScreen().addPreference(mKeyboardSettingsCategory);
- }
-
- // Build IME preference category.
- mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(getActivity());
-
- mKeyboardSettingsCategory.removeAll();
- if (!mIsOnlyImeSettings) {
- final PreferenceScreen currentIme = new PreferenceScreen(getActivity(), null);
- currentIme.setKey(KEY_CURRENT_INPUT_METHOD);
- currentIme.setTitle(getResources().getString(R.string.current_input_method));
- mKeyboardSettingsCategory.addPreference(currentIme);
+ } else {
+ final Preference pref = findPreference(KEY_CHOOSE_INPUT_METHODS);
+ final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
+ intent.setClass(activity, SubSettings.class);
+ intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, getClass().getName());
+ intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
+ R.string.choose_input_methods);
+ pref.setIntent(intent);
}
// Build hard keyboard and game controller preference categories.
- mIm = (InputManager)getActivity().getSystemService(Context.INPUT_SERVICE);
+ mIm = (InputManager)activity.getSystemService(Context.INPUT_SERVICE);
updateInputDevices();
// Spell Checker
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setClass(getActivity(), SpellCheckersSettingsActivity.class);
final SpellCheckersPreference scp = ((SpellCheckersPreference)findPreference(
"spellcheckers_settings"));
if (scp != null) {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(activity, SpellCheckersSettingsActivity.class);
scp.setFragmentIntent(this, intent);
}
mHandler = new Handler();
- mSettingsObserver = new SettingsObserver(mHandler, getActivity());
+ mSettingsObserver = new SettingsObserver(mHandler, activity);
}
private void updateInputMethodSelectorSummary(int value) {
@@ -246,7 +239,7 @@
mSettingsObserver.resume();
mIm.registerInputDeviceListener(this, null);
- if (!mIsOnlyImeSettings) {
+ if (!mShowsOnlyFullImeAndKeyboardList) {
if (mLanguagePref != null) {
String localeName = getLocaleName(getResources());
mLanguagePref.setSummary(localeName);
@@ -419,31 +412,33 @@
private void updateInputMethodPreferenceViews() {
synchronized (mInputMethodPreferenceList) {
// Clear existing "InputMethodPreference"s
- for (final InputMethodPreference imp : mInputMethodPreferenceList) {
- mKeyboardSettingsCategory.removePreference(imp);
+ for (final InputMethodPreference pref : mInputMethodPreferenceList) {
+ mKeyboardSettingsCategory.removePreference(pref);
}
mInputMethodPreferenceList.clear();
- final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList();
+ final Context context = getActivity();
+ final List<InputMethodInfo> imis = mShowsOnlyFullImeAndKeyboardList
+ ? mInputMethodSettingValues.getInputMethodList()
+ : mImm.getEnabledInputMethodList();
final int N = (imis == null ? 0 : imis.size());
for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = imis.get(i);
- final InputMethodPreference pref = getInputMethodPreference(imi);
- pref.setOnImePreferenceChangeListener(mOnImePreferenceChangedListener);
+ final InputMethodPreference pref = new InputMethodPreference(
+ context, imi, mShowsOnlyFullImeAndKeyboardList /* hasSwitch */, this);
mInputMethodPreferenceList.add(pref);
}
-
- if (!mInputMethodPreferenceList.isEmpty()) {
- Collections.sort(mInputMethodPreferenceList);
- for (int i = 0; i < N; ++i) {
- mKeyboardSettingsCategory.addPreference(mInputMethodPreferenceList.get(i));
+ final Collator collator = Collator.getInstance();
+ Collections.sort(mInputMethodPreferenceList, new Comparator<InputMethodPreference>() {
+ @Override
+ public int compare(InputMethodPreference lhs, InputMethodPreference rhs) {
+ return lhs.compareTo(rhs, collator);
}
- }
-
- // update views status
- for (Preference pref : mInputMethodPreferenceList) {
- if (pref instanceof InputMethodPreference) {
- ((InputMethodPreference) pref).updatePreferenceViews();
- }
+ });
+ for (int i = 0; i < N; ++i) {
+ final InputMethodPreference pref = mInputMethodPreferenceList.get(i);
+ mKeyboardSettingsCategory.addPreference(pref);
+ InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
+ pref.updatePreferenceViews();
}
}
updateCurrentImeName();
@@ -456,6 +451,19 @@
mInputMethodSettingValues.getInputMethodList(), null);
}
+ @Override
+ public void onSaveInputMethodPreference(final InputMethodPreference pref) {
+ final boolean hasHardwareKeyboard = getResources().getConfiguration().keyboard
+ == Configuration.KEYBOARD_QWERTY;
+ InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(this, getContentResolver(),
+ mImm.getInputMethodList(), hasHardwareKeyboard);
+ // Update input method settings and preference list.
+ mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
+ for (final InputMethodPreference p : mInputMethodPreferenceList) {
+ p.updatePreferenceViews();
+ }
+ }
+
private void updateCurrentImeName() {
final Context context = getActivity();
if (context == null || mImm == null) return;
@@ -471,26 +479,6 @@
}
}
- private InputMethodPreference getInputMethodPreference(InputMethodInfo imi) {
- final PackageManager pm = getPackageManager();
- final CharSequence label = imi.loadLabel(pm);
- // IME settings
- final Intent intent;
- final String settingsActivity = imi.getSettingsActivity();
- if (!TextUtils.isEmpty(settingsActivity)) {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.setClassName(imi.getPackageName(), settingsActivity);
- } else {
- intent = null;
- }
-
- // Add a check box for enabling/disabling IME
- final InputMethodPreference pref = new InputMethodPreference(this, intent, mImm, imi);
- pref.setKey(imi.getId());
- pref.setTitle(label);
- return pref;
- }
-
private void updateInputDevices() {
updateHardKeyboards();
updateGameControllers();
@@ -643,7 +631,7 @@
if (context.getAssets().getLocales().length > 1) {
String localeName = getLocaleName(resources);
SearchIndexableRaw indexable = new SearchIndexableRaw(context);
- indexable.key = "phone_language";
+ indexable.key = KEY_PHONE_LANGUAGE;
indexable.title = context.getString(R.string.phone_language);
indexable.summaryOn = localeName;
indexable.summaryOff = localeName;
@@ -681,7 +669,7 @@
// Current IME.
String currImeName = immValues.getCurrentInputMethodName(context).toString();
indexable = new SearchIndexableRaw(context);
- indexable.key = "current_input_method";
+ indexable.key = KEY_CURRENT_INPUT_METHOD;
indexable.title = context.getString(R.string.current_input_method);
indexable.summaryOn = currImeName;
indexable.summaryOff = currImeName;
diff --git a/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java b/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java
index bf3a601..f4e66d2 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndSubtypeUtil.java
@@ -16,13 +16,12 @@
package com.android.settings.inputmethod;
-import com.android.internal.inputmethod.InputMethodUtils;
-import com.android.settings.SettingsPreferenceFragment;
-
import android.content.ContentResolver;
+import android.content.SharedPreferences;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
+import android.preference.TwoStatePreference;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
@@ -30,6 +29,9 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.inputmethod.InputMethodUtils;
+import com.android.settings.SettingsPreferenceFragment;
+
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -163,10 +165,10 @@
final String imiId = imi.getId();
Preference pref = context.findPreference(imiId);
if (pref == null) continue;
- // In the Configure input method screen or in the subtype enabler screen.
- // pref is instance of CheckBoxPreference in the Configure input method screen.
- final boolean isImeChecked = (pref instanceof CheckBoxPreference) ?
- ((CheckBoxPreference) pref).isChecked()
+ // 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()
: enabledIMEAndSubtypesMap.containsKey(imiId);
final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId);
final boolean systemIme = InputMethodUtils.isSystemIme(imi);
@@ -338,4 +340,15 @@
}
}
}
+
+ 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();
+ }
+ }
}
diff --git a/src/com/android/settings/inputmethod/InputMethodPreference.java b/src/com/android/settings/inputmethod/InputMethodPreference.java
old mode 100644
new mode 100755
index 87a0a77..1404875
--- a/src/com/android/settings/inputmethod/InputMethodPreference.java
+++ b/src/com/android/settings/inputmethod/InputMethodPreference.java
@@ -16,304 +16,233 @@
package com.android.settings.inputmethod;
-import com.android.internal.inputmethod.InputMethodUtils;
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
-
import android.app.AlertDialog;
-import android.app.Fragment;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.SwitchPreference;
import android.text.TextUtils;
import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.ImageView;
-import android.widget.TextView;
import android.widget.Toast;
+import com.android.internal.inputmethod.InputMethodUtils;
+import com.android.settings.R;
+
import java.text.Collator;
+import java.util.ArrayList;
import java.util.List;
-// TODO: Make this non-persistent.
-class InputMethodPreference extends CheckBoxPreference {
+/**
+ * Input method preference.
+ *
+ * This preference represents an IME. It is used for two purposes. 1) An instance with a switch
+ * is used to enable or disable the IME. 2) An instance without a switch is used to invoke the
+ * setting activity of the IME.
+ */
+class InputMethodPreference extends SwitchPreference implements OnPreferenceClickListener,
+ OnPreferenceChangeListener {
private static final String TAG = InputMethodPreference.class.getSimpleName();
- private final SettingsPreferenceFragment mFragment;
+ private static final String EMPTY_TEXT = "";
+
+ interface onSavePreferenceListener {
+ /**
+ * Called when this preference needs to be saved its state.
+ *
+ * Note that this preference is non-persistent and needs explicitly to be saved its state.
+ * Because changing one IME state may change other IMEs' state, this is a place to update
+ * other IMEs' state as well.
+ *
+ * @param pref This preference.
+ */
+ public void onSaveInputMethodPreference(InputMethodPreference pref);
+ }
+
private final InputMethodInfo mImi;
- private final InputMethodManager mImm;
- private final boolean mIsValidSystemNonAuxAsciiCapableIme;
- private final Intent mSettingsIntent;
- private final boolean mIsSystemIme;
- private final Collator mCollator;
+ private final boolean mHasPriorityInSorting;
+ private final onSavePreferenceListener mOnSaveListener;
+ private final InputMethodSettingValuesWrapper mInputMethodSettingValues;
private AlertDialog mDialog = null;
- private ImageView mInputMethodSettingsButton;
- private TextView mTitleText;
- private TextView mSummaryText;
- private View mInputMethodPref;
- private OnPreferenceChangeListener mOnImePreferenceChangeListener;
- private final OnClickListener mPrefOnclickListener = new OnClickListener() {
- @Override
- public void onClick(View arg0) {
- if (!isEnabled()) {
- return;
- }
- if (isChecked()) {
- setChecked(false, true /* save */);
- } else {
- if (mIsSystemIme) {
- setChecked(true, true /* save */);
- } else {
- showSecurityWarnDialog(mImi, InputMethodPreference.this);
- }
- }
- }
- };
-
- public InputMethodPreference(SettingsPreferenceFragment fragment, Intent settingsIntent,
- InputMethodManager imm, InputMethodInfo imi) {
- super(fragment.getActivity());
- setLayoutResource(R.layout.preference_inputmethod);
- setWidgetLayoutResource(R.layout.preference_inputmethod_widget);
- mFragment = fragment;
- mSettingsIntent = settingsIntent;
- mImm = imm;
+ /**
+ * A preference entry of an input method.
+ *
+ * @param context The Context this is associated with.
+ * @param imi The {@link InputMethodInfo} of this preference.
+ * @param isImeEnabler true if this preference is the IME enabler that has enable/disable
+ * switches for all available IMEs, not the list of enabled IMEs.
+ * @param onSaveListener The listener called when this preference has been changed and needs
+ * to save the state to shared preference.
+ */
+ InputMethodPreference(final Context context, final InputMethodInfo imi,
+ final boolean isImeEnabler, final onSavePreferenceListener onSaveListener) {
+ super(context);
+ setPersistent(false);
mImi = imi;
- mIsSystemIme = InputMethodUtils.isSystemIme(imi);
- mCollator = Collator.getInstance(fragment.getResources().getConfiguration().locale);
- final Context context = fragment.getActivity();
- mIsValidSystemNonAuxAsciiCapableIme = InputMethodSettingValuesWrapper
- .getInstance(context).isValidSystemNonAuxAsciiCapableIme(imi, context);
- updatePreferenceViews();
+ mOnSaveListener = onSaveListener;
+ if (!isImeEnabler) {
+ // Hide switch widget.
+ setWidgetLayoutResource(0 /* widgetLayoutResId */);
+ }
+ // Disable on/off switch texts.
+ setSwitchTextOn(EMPTY_TEXT);
+ setSwitchTextOff(EMPTY_TEXT);
+ setKey(imi.getId());
+ setTitle(imi.loadLabel(context.getPackageManager()));
+ final String settingsActivity = imi.getSettingsActivity();
+ if (TextUtils.isEmpty(settingsActivity)) {
+ setIntent(null);
+ } else {
+ // Set an intent to invoke settings activity of an input method.
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName(imi.getPackageName(), settingsActivity);
+ setIntent(intent);
+ }
+ mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(context);
+ mHasPriorityInSorting = InputMethodUtils.isSystemIme(imi)
+ && mInputMethodSettingValues.isValidSystemNonAuxAsciiCapableIme(imi, context);
+ setOnPreferenceClickListener(this);
+ setOnPreferenceChangeListener(this);
+ }
+
+ private boolean isImeEnabler() {
+ // If this {@link SwitchPreference} doesn't have a widget layout, we explicitly hide the
+ // switch widget at constructor.
+ return getWidgetLayoutResource() != 0;
}
@Override
- protected void onBindView(View view) {
- super.onBindView(view);
- mInputMethodPref = view.findViewById(R.id.inputmethod_pref);
- mInputMethodPref.setOnClickListener(mPrefOnclickListener);
- mInputMethodSettingsButton = (ImageView)view.findViewById(R.id.inputmethod_settings);
- mTitleText = (TextView)view.findViewById(android.R.id.title);
- mSummaryText = (TextView)view.findViewById(android.R.id.summary);
- final boolean hasSubtypes = mImi.getSubtypeCount() > 1;
- final String imiId = mImi.getId();
- if (hasSubtypes) {
- mInputMethodPref.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View arg0) {
- final Bundle bundle = new Bundle();
- bundle.putString(android.provider.Settings.EXTRA_INPUT_METHOD_ID, imiId);
- startFragment(mFragment, InputMethodAndSubtypeEnabler.class.getName(),
- 0, bundle);
- return true;
- }
- });
- }
-
- if (mSettingsIntent != null) {
- mInputMethodSettingsButton.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View arg0) {
- try {
- mFragment.startActivity(mSettingsIntent);
- } catch (ActivityNotFoundException e) {
- Log.d(TAG, "IME's Settings Activity Not Found: " + e);
- final String msg = mFragment.getString(
- R.string.failed_to_open_app_settings_toast,
- mImi.loadLabel(
- mFragment.getActivity().getPackageManager()));
- Toast.makeText(
- mFragment.getActivity(), msg, Toast.LENGTH_LONG).show();
- }
- }
- });
- }
- if (hasSubtypes) {
- final OnLongClickListener listener = new OnLongClickListener() {
- @Override
- public boolean onLongClick(View arg0) {
- final Bundle bundle = new Bundle();
- bundle.putString(android.provider.Settings.EXTRA_INPUT_METHOD_ID, imiId);
- startFragment(mFragment, InputMethodAndSubtypeEnabler.class.getName(),
- 0, bundle);
- return true;
- }
- };
- mInputMethodSettingsButton.setOnLongClickListener(listener);
- }
- if (mSettingsIntent == null) {
- mInputMethodSettingsButton.setVisibility(View.GONE);
- }
- updatePreferenceViews();
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- updatePreferenceViews();
- }
-
- public void updatePreferenceViews() {
- final boolean isAlwaysChecked =
- InputMethodSettingValuesWrapper.getInstance(getContext()).isAlwaysCheckedIme(
- mImi, getContext());
- if (isAlwaysChecked) {
- super.setChecked(true);
- super.setEnabled(false);
- } else {
- super.setEnabled(true);
- }
- final boolean checked = isChecked();
- if (mInputMethodSettingsButton != null) {
- mInputMethodSettingsButton.setEnabled(checked);
- mInputMethodSettingsButton.setClickable(checked);
- mInputMethodSettingsButton.setFocusable(checked);
- if (!checked) {
- mInputMethodSettingsButton.setAlpha(Utils.DISABLED_ALPHA);
- }
- }
- if (mTitleText != null) {
- mTitleText.setEnabled(true);
- }
- if (mSummaryText != null) {
- mSummaryText.setEnabled(checked);
- }
- if (mInputMethodPref != null) {
- mInputMethodPref.setEnabled(true);
- mInputMethodPref.setLongClickable(checked);
- final boolean enabled = isEnabled();
- mInputMethodPref.setOnClickListener(enabled ? mPrefOnclickListener : null);
- if (!enabled) {
- mInputMethodPref.setBackgroundColor(0);
- }
- }
- updateSummary();
- }
-
- public static boolean startFragment(
- Fragment fragment, String fragmentClass, int requestCode, Bundle extras) {
- if (fragment.getActivity() instanceof SettingsActivity) {
- SettingsActivity sa = (SettingsActivity) fragment.getActivity();
- sa.startPreferencePanel(fragmentClass, extras, 0, null, fragment, requestCode);
- return true;
- } else {
- Log.w(TAG, "Parent isn't Settings, thus there's no way to launch the "
- + "given Fragment (name: " + fragmentClass + ", requestCode: " + requestCode
- + ")");
+ public boolean onPreferenceChange(final Preference preference, final Object newValue) {
+ // Always returns false to prevent default behavior.
+ // See {@link TwoStatePreference#onClick()}.
+ if (!isImeEnabler()) {
+ // Prevent disabling an IME because this preference is for invoking a settings activity.
return false;
}
+ if (isChecked()) {
+ // Disable this IME.
+ setChecked(false);
+ mOnSaveListener.onSaveInputMethodPreference(this);
+ return false;
+ }
+ if (InputMethodUtils.isSystemIme(mImi)) {
+ // Enable a system IME. No need to show a security warning dialog.
+ setChecked(true);
+ mOnSaveListener.onSaveInputMethodPreference(this);
+ return false;
+ }
+ // Enable a 3rd party IME.
+ showSecurityWarnDialog(mImi);
+ return false;
+ }
+
+ @Override
+ public boolean onPreferenceClick(final Preference preference) {
+ // Always returns true to prevent invoking an intent without catching exceptions.
+ // See {@link Preference#performClick(PreferenceScreen)}/
+ if (isImeEnabler()) {
+ // Prevent invoking a settings activity because this preference is for enabling and
+ // disabling an input method.
+ return true;
+ }
+ final Context context = getContext();
+ try {
+ final Intent intent = getIntent();
+ if (intent != null) {
+ // Invoke a settings activity of an input method.
+ context.startActivity(intent);
+ }
+ } catch (final ActivityNotFoundException e) {
+ Log.d(TAG, "IME's Settings Activity Not Found", e);
+ final String message = context.getString(
+ R.string.failed_to_open_app_settings_toast,
+ mImi.loadLabel(context.getPackageManager()));
+ Toast.makeText(context, message, Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+
+ void updatePreferenceViews() {
+ final boolean isAlwaysChecked = mInputMethodSettingValues.isAlwaysCheckedIme(
+ mImi, getContext());
+ // Only when this preference has a switch and an input method should be always enabled,
+ // this preference should be disabled to prevent accidentally disabling an input method.
+ setEnabled(!(isAlwaysChecked && isImeEnabler()));
+ setChecked(mInputMethodSettingValues.isEnabledImi(mImi));
+ setSummary(getSummaryString());
+ }
+
+ private InputMethodManager getInputMethodManager() {
+ return (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
}
private String getSummaryString() {
- final StringBuilder builder = new StringBuilder();
- final List<InputMethodSubtype> subtypes = mImm.getEnabledInputMethodSubtypeList(mImi, true);
- for (InputMethodSubtype subtype : subtypes) {
- if (builder.length() > 0) {
- builder.append(", ");
- }
- final CharSequence subtypeLabel = subtype.getDisplayName(mFragment.getActivity(),
- mImi.getPackageName(), mImi.getServiceInfo().applicationInfo);
- builder.append(subtypeLabel);
+ final Context context = getContext();
+ final InputMethodManager imm = getInputMethodManager();
+ final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(mImi, true);
+ final ArrayList<CharSequence> subtypeLabels = new ArrayList<>();
+ for (final InputMethodSubtype subtype : subtypes) {
+ final CharSequence label = subtype.getDisplayName(
+ context, mImi.getPackageName(), mImi.getServiceInfo().applicationInfo);
+ subtypeLabels.add(label);
}
- return builder.toString();
+ // TODO: A delimiter of subtype labels should be localized.
+ return TextUtils.join(", ", subtypeLabels);
}
- private void updateSummary() {
- final String summary = getSummaryString();
- if (TextUtils.isEmpty(summary)) {
- return;
- }
- setSummary(summary);
- }
-
- /**
- * Sets the checkbox state and optionally saves the settings.
- * @param checked whether to check the box
- * @param save whether to save IME settings
- */
- private void setChecked(boolean checked, boolean save) {
- final boolean wasChecked = isChecked();
- super.setChecked(checked);
- if (save) {
- saveImeSettings();
- if (wasChecked != checked && mOnImePreferenceChangeListener != null) {
- mOnImePreferenceChangeListener.onPreferenceChange(this, checked);
- }
- }
- }
-
- public void setOnImePreferenceChangeListener(OnPreferenceChangeListener listener) {
- mOnImePreferenceChangeListener = listener;
- }
-
- private void showSecurityWarnDialog(InputMethodInfo imi, final InputMethodPreference chkPref) {
+ private void showSecurityWarnDialog(final InputMethodInfo imi) {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
- mDialog = (new AlertDialog.Builder(mFragment.getActivity()))
- .setTitle(android.R.string.dialog_alert_title)
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- chkPref.setChecked(true, true);
- }
- })
- .setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- }
- })
- .create();
- mDialog.setMessage(mFragment.getResources().getString(R.string.ime_security_warning,
- imi.getServiceInfo().applicationInfo.loadLabel(
- mFragment.getActivity().getPackageManager())));
+ final Context context = getContext();
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setCancelable(true /* cancelable */);
+ builder.setTitle(android.R.string.dialog_alert_title);
+ final CharSequence label = imi.getServiceInfo().applicationInfo.loadLabel(
+ context.getPackageManager());
+ builder.setMessage(context.getString(R.string.ime_security_warning, label));
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ // The user confirmed to enable a 3rd party IME.
+ setChecked(true);
+ mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this);
+ notifyChanged();
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ // The user canceled to enable a 3rd party IME.
+ setChecked(false);
+ mOnSaveListener.onSaveInputMethodPreference(InputMethodPreference.this);
+ notifyChanged();
+ }
+ });
+ mDialog = builder.create();
mDialog.show();
}
- @Override
- public int compareTo(Preference p) {
- if (!(p instanceof InputMethodPreference)) {
- return super.compareTo(p);
- }
- final InputMethodPreference imp = (InputMethodPreference) p;
- final boolean priority0 = mIsSystemIme && mIsValidSystemNonAuxAsciiCapableIme;
- final boolean priority1 = imp.mIsSystemIme && imp.mIsValidSystemNonAuxAsciiCapableIme;
- if (priority0 == priority1) {
+ int compareTo(final InputMethodPreference rhs, final Collator collator) {
+ if (mHasPriorityInSorting == rhs.mHasPriorityInSorting) {
final CharSequence t0 = getTitle();
- final CharSequence t1 = imp.getTitle();
+ final CharSequence t1 = rhs.getTitle();
if (TextUtils.isEmpty(t0)) {
return 1;
}
if (TextUtils.isEmpty(t1)) {
return -1;
}
- return mCollator.compare(t0.toString(), t1.toString());
+ return collator.compare(t0.toString(), t1.toString());
}
// Prefer always checked system IMEs
- return priority0 ? -1 : 1;
- }
-
- private void saveImeSettings() {
- InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(
- mFragment, mFragment.getActivity().getContentResolver(), mImm.getInputMethodList(),
- mFragment.getResources().getConfiguration().keyboard
- == Configuration.KEYBOARD_QWERTY);
+ return mHasPriorityInSorting ? -1 : 1;
}
}
diff --git a/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java b/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java
index bf63487..ada476e 100644
--- a/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java
+++ b/src/com/android/settings/inputmethod/InputMethodSettingValuesWrapper.java
@@ -169,7 +169,7 @@
return count;
}
- private boolean isEnabledImi(InputMethodInfo imi) {
+ boolean isEnabledImi(InputMethodInfo imi) {
final List<InputMethodInfo> enabledImis;
synchronized (mMethodMap) {
enabledImis = mSettings.getEnabledInputMethodListLocked();