InputMethodAndLanguageSettings.java revision 9bcc60704991879a0f8c9098eef26233942d6fe2
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.inputmethod; 18 19import com.android.settings.R; 20import com.android.settings.Settings.SpellCheckersSettingsActivity; 21import com.android.settings.SettingsPreferenceFragment; 22import com.android.settings.Utils; 23import com.android.settings.VoiceInputOutputSettings; 24 25import android.app.Activity; 26import android.content.ContentResolver; 27import android.content.Context; 28import android.content.Intent; 29import android.content.pm.PackageManager; 30import android.content.res.Configuration; 31import android.database.ContentObserver; 32import android.os.Bundle; 33import android.os.Handler; 34import android.preference.CheckBoxPreference; 35import android.preference.ListPreference; 36import android.preference.Preference; 37import android.preference.PreferenceCategory; 38import android.preference.PreferenceGroup; 39import android.preference.PreferenceScreen; 40import android.provider.Settings; 41import android.provider.Settings.System; 42import android.text.TextUtils; 43import android.view.inputmethod.InputMethodInfo; 44import android.view.inputmethod.InputMethodManager; 45 46import java.util.ArrayList; 47import java.util.Collections; 48import java.util.List; 49import java.util.Set; 50 51public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment 52 implements Preference.OnPreferenceChangeListener{ 53 54 private static final String KEY_PHONE_LANGUAGE = "phone_language"; 55 private static final String KEY_CURRENT_INPUT_METHOD = "current_input_method"; 56 private static final String KEY_INPUT_METHOD_SELECTOR = "input_method_selector"; 57 private static final String KEY_USER_DICTIONARY_SETTINGS = "key_user_dictionary_settings"; 58 // false: on ICS or later 59 private static final boolean SHOW_INPUT_METHOD_SWITCHER_SETTINGS = false; 60 61 private static final String[] sSystemSettingNames = { 62 System.TEXT_AUTO_REPLACE, System.TEXT_AUTO_CAPS, System.TEXT_AUTO_PUNCTUATE, 63 }; 64 65 private static final String[] sHardKeyboardKeys = { 66 "auto_replace", "auto_caps", "auto_punctuate", 67 }; 68 69 private int mDefaultInputMethodSelectorVisibility = 0; 70 private ListPreference mShowInputMethodSelectorPref; 71 private Preference mLanguagePref; 72 private ArrayList<InputMethodPreference> mInputMethodPreferenceList = 73 new ArrayList<InputMethodPreference>(); 74 private boolean mHaveHardKeyboard; 75 private PreferenceCategory mHardKeyboardCategory; 76 private InputMethodManager mImm; 77 private List<InputMethodInfo> mImis; 78 private boolean mIsOnlyImeSettings; 79 private Handler mHandler; 80 @SuppressWarnings("unused") 81 private SettingsObserver mSettingsObserver; 82 83 @Override 84 public void onCreate(Bundle icicle) { 85 super.onCreate(icicle); 86 87 addPreferencesFromResource(R.xml.language_settings); 88 89 try { 90 mDefaultInputMethodSelectorVisibility = Integer.valueOf( 91 getString(R.string.input_method_selector_visibility_default_value)); 92 } catch (NumberFormatException e) { 93 } 94 95 if (getActivity().getAssets().getLocales().length == 1) { 96 // No "Select language" pref if there's only one system locale available. 97 getPreferenceScreen().removePreference(findPreference(KEY_PHONE_LANGUAGE)); 98 } else { 99 mLanguagePref = findPreference(KEY_PHONE_LANGUAGE); 100 } 101 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 102 mShowInputMethodSelectorPref = (ListPreference)findPreference( 103 KEY_INPUT_METHOD_SELECTOR); 104 mShowInputMethodSelectorPref.setOnPreferenceChangeListener(this); 105 // TODO: Update current input method name on summary 106 updateInputMethodSelectorSummary(loadInputMethodSelectorVisibility()); 107 } 108 109 new VoiceInputOutputSettings(this).onCreate(); 110 111 // Hard keyboard 112 final Configuration config = getResources().getConfiguration(); 113 mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); 114 115 // IME 116 mIsOnlyImeSettings = Settings.ACTION_INPUT_METHOD_SETTINGS.equals( 117 getActivity().getIntent().getAction()); 118 getActivity().getIntent().setAction(null); 119 mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 120 mImis = mImm.getInputMethodList(); 121 createImePreferenceHierarchy((PreferenceGroup)findPreference("keyboard_settings_category")); 122 123 final Intent intent = new Intent(Intent.ACTION_MAIN); 124 intent.setClass(getActivity(), SpellCheckersSettingsActivity.class); 125 final SpellCheckersPreference scp = ((SpellCheckersPreference)findPreference( 126 "spellcheckers_settings")); 127 if (scp != null) { 128 scp.setFragmentIntent(this, intent); 129 } 130 131 mHandler = new Handler(); 132 mSettingsObserver = new SettingsObserver(mHandler, getActivity()); 133 } 134 135 private void updateInputMethodSelectorSummary(int value) { 136 String[] inputMethodSelectorTitles = getResources().getStringArray( 137 R.array.input_method_selector_titles); 138 if (inputMethodSelectorTitles.length > value) { 139 mShowInputMethodSelectorPref.setSummary(inputMethodSelectorTitles[value]); 140 mShowInputMethodSelectorPref.setValue(String.valueOf(value)); 141 } 142 } 143 144 private void updateUserDictionaryPreference(Preference userDictionaryPreference) { 145 final Activity activity = getActivity(); 146 final Set<String> localeList = UserDictionaryList.getUserDictionaryLocalesList(activity); 147 if (null == localeList) { 148 // The locale list is null if and only if the user dictionary service is 149 // not present or disabled. In this case we need to remove the preference. 150 getPreferenceScreen().removePreference(userDictionaryPreference); 151 } else if (localeList.size() <= 1) { 152 final Intent intent = 153 new Intent(UserDictionaryList.USER_DICTIONARY_SETTINGS_INTENT_ACTION); 154 userDictionaryPreference.setTitle(R.string.user_dict_single_settings_title); 155 userDictionaryPreference.setIntent(intent); 156 // If the size of localeList is 0, we don't set the locale parameter in the 157 // extras. This will be interpreted by the UserDictionarySettings class as 158 // meaning "the current locale". 159 // Note that with the current code for UserDictionaryList#getUserDictionaryLocalesList() 160 // the locale list always has at least one element, since it always includes the current 161 // locale explicitly. @see UserDictionaryList.getUserDictionaryLocalesList(). 162 if (localeList.size() == 1) { 163 final String locale = (String)localeList.toArray()[0]; 164 userDictionaryPreference.getExtras().putString("locale", locale); 165 } 166 } else { 167 userDictionaryPreference.setTitle(R.string.user_dict_multiple_settings_title); 168 userDictionaryPreference.setFragment(UserDictionaryList.class.getName()); 169 } 170 } 171 172 @Override 173 public void onResume() { 174 super.onResume(); 175 mSettingsObserver.resume(); 176 if (!mIsOnlyImeSettings) { 177 if (mLanguagePref != null) { 178 Configuration conf = getResources().getConfiguration(); 179 String locale = conf.locale.getDisplayName(conf.locale); 180 if (locale != null && locale.length() > 1) { 181 locale = Character.toUpperCase(locale.charAt(0)) + locale.substring(1); 182 mLanguagePref.setSummary(locale); 183 } 184 } 185 186 updateUserDictionaryPreference(findPreference(KEY_USER_DICTIONARY_SETTINGS)); 187 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 188 mShowInputMethodSelectorPref.setOnPreferenceChangeListener(this); 189 } 190 } 191 192 // Hard keyboard 193 if (mHaveHardKeyboard) { 194 for (int i = 0; i < sHardKeyboardKeys.length; ++i) { 195 CheckBoxPreference chkPref = (CheckBoxPreference) 196 mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i]); 197 chkPref.setChecked( 198 System.getInt(getContentResolver(), sSystemSettingNames[i], 1) > 0); 199 } 200 } 201 202 // IME 203 InputMethodAndSubtypeUtil.loadInputMethodSubtypeList( 204 this, getContentResolver(), mImis, null); 205 updateActiveInputMethodsSummary(); 206 } 207 208 @Override 209 public void onPause() { 210 super.onPause(); 211 mSettingsObserver.pause(); 212 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 213 mShowInputMethodSelectorPref.setOnPreferenceChangeListener(null); 214 } 215 InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( 216 this, getContentResolver(), mImis, mHaveHardKeyboard); 217 } 218 219 @Override 220 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 221 // Input Method stuff 222 if (Utils.isMonkeyRunning()) { 223 return false; 224 } 225 if (preference instanceof PreferenceScreen) { 226 if (preference.getFragment() != null) { 227 // Fragment will be handled correctly by the super class. 228 } else if (KEY_CURRENT_INPUT_METHOD.equals(preference.getKey())) { 229 final InputMethodManager imm = (InputMethodManager) 230 getSystemService(Context.INPUT_METHOD_SERVICE); 231 imm.showInputMethodPicker(); 232 } 233 } else if (preference instanceof CheckBoxPreference) { 234 final CheckBoxPreference chkPref = (CheckBoxPreference) preference; 235 if (mHaveHardKeyboard) { 236 for (int i = 0; i < sHardKeyboardKeys.length; ++i) { 237 if (chkPref == mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i])) { 238 System.putInt(getContentResolver(), sSystemSettingNames[i], 239 chkPref.isChecked() ? 1 : 0); 240 return true; 241 } 242 } 243 } 244 } 245 return super.onPreferenceTreeClick(preferenceScreen, preference); 246 } 247 248 private void saveInputMethodSelectorVisibility(String value) { 249 try { 250 int intValue = Integer.valueOf(value); 251 Settings.Secure.putInt(getContentResolver(), 252 Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, intValue); 253 updateInputMethodSelectorSummary(intValue); 254 } catch(NumberFormatException e) { 255 } 256 } 257 258 private int loadInputMethodSelectorVisibility() { 259 return Settings.Secure.getInt(getContentResolver(), 260 Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, 261 mDefaultInputMethodSelectorVisibility); 262 } 263 264 @Override 265 public boolean onPreferenceChange(Preference preference, Object value) { 266 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 267 if (preference == mShowInputMethodSelectorPref) { 268 if (value instanceof String) { 269 saveInputMethodSelectorVisibility((String)value); 270 } 271 } 272 } 273 return false; 274 } 275 276 private void updateActiveInputMethodsSummary() { 277 for (Preference pref : mInputMethodPreferenceList) { 278 if (pref instanceof InputMethodPreference) { 279 ((InputMethodPreference)pref).updateSummary(); 280 } 281 } 282 updateCurrentImeName(); 283 } 284 285 private void updateCurrentImeName() { 286 final Context context = getActivity(); 287 if (context == null || mImm == null) return; 288 final Preference curPref = getPreferenceScreen().findPreference(KEY_CURRENT_INPUT_METHOD); 289 if (curPref != null) { 290 final CharSequence curIme = InputMethodAndSubtypeUtil.getCurrentInputMethodName( 291 context, getContentResolver(), mImm, mImis, getPackageManager()); 292 if (!TextUtils.isEmpty(curIme)) { 293 synchronized(this) { 294 curPref.setSummary(curIme); 295 } 296 } 297 } 298 } 299 300 private InputMethodPreference getInputMethodPreference(InputMethodInfo imi, int imiSize) { 301 final PackageManager pm = getPackageManager(); 302 final CharSequence label = imi.loadLabel(pm); 303 // IME settings 304 final Intent intent; 305 final String settingsActivity = imi.getSettingsActivity(); 306 if (!TextUtils.isEmpty(settingsActivity)) { 307 intent = new Intent(Intent.ACTION_MAIN); 308 intent.setClassName(imi.getPackageName(), settingsActivity); 309 } else { 310 intent = null; 311 } 312 313 // Add a check box for enabling/disabling IME 314 InputMethodPreference pref = new InputMethodPreference(this, intent, mImm, imi, imiSize); 315 pref.setKey(imi.getId()); 316 pref.setTitle(label); 317 return pref; 318 } 319 320 private void createImePreferenceHierarchy(PreferenceGroup root) { 321 final Preference hardKeyPref = findPreference("hard_keyboard"); 322 if (mIsOnlyImeSettings) { 323 getPreferenceScreen().removeAll(); 324 if (hardKeyPref != null && mHaveHardKeyboard) { 325 getPreferenceScreen().addPreference(hardKeyPref); 326 } 327 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 328 getPreferenceScreen().addPreference(mShowInputMethodSelectorPref); 329 } 330 getPreferenceScreen().addPreference(root); 331 } 332 if (hardKeyPref != null) { 333 if (mHaveHardKeyboard) { 334 mHardKeyboardCategory = (PreferenceCategory) hardKeyPref; 335 } else { 336 getPreferenceScreen().removePreference(hardKeyPref); 337 } 338 } 339 root.removeAll(); 340 mInputMethodPreferenceList.clear(); 341 342 if (!mIsOnlyImeSettings) { 343 // Current IME selection 344 final PreferenceScreen currentIme = new PreferenceScreen(getActivity(), null); 345 currentIme.setKey(KEY_CURRENT_INPUT_METHOD); 346 currentIme.setTitle(getResources().getString(R.string.current_input_method)); 347 root.addPreference(currentIme); 348 } 349 350 final int N = (mImis == null ? 0 : mImis.size()); 351 for (int i = 0; i < N; ++i) { 352 final InputMethodInfo imi = mImis.get(i); 353 final InputMethodPreference pref = getInputMethodPreference(imi, N); 354 mInputMethodPreferenceList.add(pref); 355 } 356 357 Collections.sort(mInputMethodPreferenceList); 358 for (int i = 0; i < N; ++i) { 359 root.addPreference(mInputMethodPreferenceList.get(i)); 360 } 361 } 362 363 private class SettingsObserver extends ContentObserver { 364 private Context mContext; 365 366 public SettingsObserver(Handler handler, Context context) { 367 super(handler); 368 mContext = context; 369 } 370 371 @Override public void onChange(boolean selfChange) { 372 updateCurrentImeName(); 373 } 374 375 public void resume() { 376 final ContentResolver cr = mContext.getContentResolver(); 377 cr.registerContentObserver( 378 Settings.Secure.getUriFor(Settings.Secure.DEFAULT_INPUT_METHOD), false, this); 379 cr.registerContentObserver(Settings.Secure.getUriFor( 380 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this); 381 } 382 383 public void pause() { 384 mContext.getContentResolver().unregisterContentObserver(this); 385 } 386 } 387} 388