/* * Copyright (C) 2008 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 com.android.settings.R; import com.android.settings.Settings.SpellCheckersSettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.VoiceInputOutputSettings; import android.app.Activity; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.ContentObserver; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Settings; import android.provider.Settings.System; import android.text.TextUtils; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener{ private static final String KEY_PHONE_LANGUAGE = "phone_language"; 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"; // false: on ICS or later private static final boolean SHOW_INPUT_METHOD_SWITCHER_SETTINGS = false; private static final String[] sSystemSettingNames = { System.TEXT_AUTO_REPLACE, System.TEXT_AUTO_CAPS, System.TEXT_AUTO_PUNCTUATE, }; private static final String[] sHardKeyboardKeys = { "auto_replace", "auto_caps", "auto_punctuate", }; private int mDefaultInputMethodSelectorVisibility = 0; private ListPreference mShowInputMethodSelectorPref; private Preference mLanguagePref; private ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<InputMethodPreference>(); private boolean mHaveHardKeyboard; private PreferenceCategory mHardKeyboardCategory; private InputMethodManager mImm; private List<InputMethodInfo> mImis; private boolean mIsOnlyImeSettings; private Handler mHandler; @SuppressWarnings("unused") private SettingsObserver mSettingsObserver; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.language_settings); try { mDefaultInputMethodSelectorVisibility = Integer.valueOf( getString(R.string.input_method_selector_visibility_default_value)); } catch (NumberFormatException e) { } if (getActivity().getAssets().getLocales().length == 1) { // No "Select language" pref if there's only one system locale available. getPreferenceScreen().removePreference(findPreference(KEY_PHONE_LANGUAGE)); } else { mLanguagePref = findPreference(KEY_PHONE_LANGUAGE); } if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { mShowInputMethodSelectorPref = (ListPreference)findPreference( KEY_INPUT_METHOD_SELECTOR); mShowInputMethodSelectorPref.setOnPreferenceChangeListener(this); // TODO: Update current input method name on summary updateInputMethodSelectorSummary(loadInputMethodSelectorVisibility()); } new VoiceInputOutputSettings(this).onCreate(); // Hard keyboard final Configuration config = getResources().getConfiguration(); mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); // IME mIsOnlyImeSettings = Settings.ACTION_INPUT_METHOD_SETTINGS.equals( getActivity().getIntent().getAction()); getActivity().getIntent().setAction(null); mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); mImis = mImm.getInputMethodList(); createImePreferenceHierarchy((PreferenceGroup)findPreference("keyboard_settings_category")); final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClass(getActivity(), SpellCheckersSettingsActivity.class); final SpellCheckersPreference scp = ((SpellCheckersPreference)findPreference( "spellcheckers_settings")); if (scp != null) { scp.setFragmentIntent(this, intent); } mHandler = new Handler(); mSettingsObserver = new SettingsObserver(mHandler, getActivity()); } private void updateInputMethodSelectorSummary(int value) { String[] inputMethodSelectorTitles = getResources().getStringArray( R.array.input_method_selector_titles); if (inputMethodSelectorTitles.length > value) { mShowInputMethodSelectorPref.setSummary(inputMethodSelectorTitles[value]); mShowInputMethodSelectorPref.setValue(String.valueOf(value)); } } private void updateUserDictionaryPreference(Preference userDictionaryPreference) { final Activity activity = getActivity(); final Set<String> localeList = UserDictionaryList.getUserDictionaryLocalesList(activity); if (null == localeList) { // The locale list is null if and only if the user dictionary service is // not present or disabled. In this case we need to remove the preference. getPreferenceScreen().removePreference(userDictionaryPreference); } else if (localeList.size() <= 1) { final Intent intent = new Intent(UserDictionaryList.USER_DICTIONARY_SETTINGS_INTENT_ACTION); userDictionaryPreference.setTitle(R.string.user_dict_single_settings_title); userDictionaryPreference.setIntent(intent); // If the size of localeList is 0, we don't set the locale parameter in the // extras. This will be interpreted by the UserDictionarySettings class as // meaning "the current locale". // Note that with the current code for UserDictionaryList#getUserDictionaryLocalesList() // the locale list always has at least one element, since it always includes the current // locale explicitly. @see UserDictionaryList.getUserDictionaryLocalesList(). if (localeList.size() == 1) { final String locale = (String)localeList.toArray()[0]; userDictionaryPreference.getExtras().putString("locale", locale); } } else { userDictionaryPreference.setTitle(R.string.user_dict_multiple_settings_title); userDictionaryPreference.setFragment(UserDictionaryList.class.getName()); } } @Override public void onResume() { super.onResume(); if (!mIsOnlyImeSettings) { if (mLanguagePref != null) { Configuration conf = getResources().getConfiguration(); String locale = conf.locale.getDisplayName(conf.locale); if (locale != null && locale.length() > 1) { locale = Character.toUpperCase(locale.charAt(0)) + locale.substring(1); mLanguagePref.setSummary(locale); } } updateUserDictionaryPreference(findPreference(KEY_USER_DICTIONARY_SETTINGS)); if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { mShowInputMethodSelectorPref.setOnPreferenceChangeListener(this); } } // Hard keyboard if (mHaveHardKeyboard) { for (int i = 0; i < sHardKeyboardKeys.length; ++i) { CheckBoxPreference chkPref = (CheckBoxPreference) mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i]); chkPref.setChecked( System.getInt(getContentResolver(), sSystemSettingNames[i], 1) > 0); } } // IME InputMethodAndSubtypeUtil.loadInputMethodSubtypeList( this, getContentResolver(), mImis, null); updateActiveInputMethodsSummary(); } @Override public void onPause() { super.onPause(); if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { mShowInputMethodSelectorPref.setOnPreferenceChangeListener(null); } InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( this, getContentResolver(), mImis, mHaveHardKeyboard); } @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { // Input Method stuff if (Utils.isMonkeyRunning()) { return false; } if (preference instanceof PreferenceScreen) { if (preference.getFragment() != null) { // Fragment will be handled correctly by the super class. } else if (KEY_CURRENT_INPUT_METHOD.equals(preference.getKey())) { final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.showInputMethodPicker(); } } else if (preference instanceof CheckBoxPreference) { final CheckBoxPreference chkPref = (CheckBoxPreference) preference; if (mHaveHardKeyboard) { for (int i = 0; i < sHardKeyboardKeys.length; ++i) { if (chkPref == mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i])) { System.putInt(getContentResolver(), sSystemSettingNames[i], chkPref.isChecked() ? 1 : 0); return true; } } } } return super.onPreferenceTreeClick(preferenceScreen, preference); } private void saveInputMethodSelectorVisibility(String value) { try { int intValue = Integer.valueOf(value); Settings.Secure.putInt(getContentResolver(), Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, intValue); updateInputMethodSelectorSummary(intValue); } catch(NumberFormatException e) { } } private int loadInputMethodSelectorVisibility() { return Settings.Secure.getInt(getContentResolver(), Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, mDefaultInputMethodSelectorVisibility); } @Override public boolean onPreferenceChange(Preference preference, Object value) { if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { if (preference == mShowInputMethodSelectorPref) { if (value instanceof String) { saveInputMethodSelectorVisibility((String)value); } } } return false; } private void updateActiveInputMethodsSummary() { for (Preference pref : mInputMethodPreferenceList) { if (pref instanceof InputMethodPreference) { ((InputMethodPreference)pref).updateSummary(); } } updateCurrentImeName(); } private void updateCurrentImeName() { final Context context = getActivity(); if (context == null || mImm == null) return; final Preference curPref = getPreferenceScreen().findPreference(KEY_CURRENT_INPUT_METHOD); if (curPref != null) { final CharSequence curIme = InputMethodAndSubtypeUtil.getCurrentInputMethodName( context, getContentResolver(), mImm, mImis, getPackageManager()); if (!TextUtils.isEmpty(curIme)) { synchronized(this) { curPref.setSummary(curIme); } } } } private InputMethodPreference getInputMethodPreference(InputMethodInfo imi, int imiSize) { 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 InputMethodPreference pref = new InputMethodPreference(this, intent, mImm, imi, imiSize); pref.setKey(imi.getId()); pref.setTitle(label); return pref; } private void createImePreferenceHierarchy(PreferenceGroup root) { final Preference hardKeyPref = findPreference("hard_keyboard"); if (mIsOnlyImeSettings) { getPreferenceScreen().removeAll(); if (hardKeyPref != null && mHaveHardKeyboard) { getPreferenceScreen().addPreference(hardKeyPref); } if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { getPreferenceScreen().addPreference(mShowInputMethodSelectorPref); } getPreferenceScreen().addPreference(root); } if (hardKeyPref != null) { if (mHaveHardKeyboard) { mHardKeyboardCategory = (PreferenceCategory) hardKeyPref; } else { getPreferenceScreen().removePreference(hardKeyPref); } } root.removeAll(); mInputMethodPreferenceList.clear(); if (!mIsOnlyImeSettings) { // Current IME selection final PreferenceScreen currentIme = new PreferenceScreen(getActivity(), null); currentIme.setKey(KEY_CURRENT_INPUT_METHOD); currentIme.setTitle(getResources().getString(R.string.current_input_method)); root.addPreference(currentIme); } final int N = (mImis == null ? 0 : mImis.size()); for (int i = 0; i < N; ++i) { final InputMethodInfo imi = mImis.get(i); final InputMethodPreference pref = getInputMethodPreference(imi, N); mInputMethodPreferenceList.add(pref); } Collections.sort(mInputMethodPreferenceList); for (int i = 0; i < N; ++i) { root.addPreference(mInputMethodPreferenceList.get(i)); } } private class SettingsObserver extends ContentObserver { public SettingsObserver(Handler handler, Context context) { super(handler); final ContentResolver cr = context.getContentResolver(); cr.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.DEFAULT_INPUT_METHOD), false, this); cr.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this); } @Override public void onChange(boolean selfChange) { updateCurrentImeName(); } } }