InputMethodAndLanguageSettings.java revision 813a54d216010a16d714355c61d606dd3eb589aa
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.KeyboardLayoutPickerActivity; 21import com.android.settings.Settings.SpellCheckersSettingsActivity; 22import com.android.settings.SettingsPreferenceFragment; 23import com.android.settings.UserDictionarySettings; 24import com.android.settings.Utils; 25import com.android.settings.VoiceInputOutputSettings; 26 27import android.app.Activity; 28import android.app.Fragment; 29import android.content.ContentResolver; 30import android.content.Context; 31import android.content.Intent; 32import android.content.pm.PackageManager; 33import android.content.res.Configuration; 34import android.content.res.Resources; 35import android.database.ContentObserver; 36import android.hardware.input.InputDeviceIdentifier; 37import android.hardware.input.InputManager; 38import android.hardware.input.KeyboardLayout; 39import android.os.Bundle; 40import android.os.Handler; 41import android.preference.CheckBoxPreference; 42import android.preference.ListPreference; 43import android.preference.Preference; 44import android.preference.Preference.OnPreferenceChangeListener; 45import android.preference.Preference.OnPreferenceClickListener; 46import android.preference.PreferenceCategory; 47import android.preference.PreferenceScreen; 48import android.provider.Settings; 49import android.provider.Settings.System; 50import android.text.TextUtils; 51import android.view.InputDevice; 52import android.view.inputmethod.InputMethodInfo; 53import android.view.inputmethod.InputMethodManager; 54import android.widget.BaseAdapter; 55 56import java.util.ArrayList; 57import java.util.Collections; 58import java.util.List; 59import java.util.TreeSet; 60 61public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment 62 implements Preference.OnPreferenceChangeListener, InputManager.InputDeviceListener, 63 KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener { 64 65 private static final String KEY_PHONE_LANGUAGE = "phone_language"; 66 private static final String KEY_CURRENT_INPUT_METHOD = "current_input_method"; 67 private static final String KEY_INPUT_METHOD_SELECTOR = "input_method_selector"; 68 private static final String KEY_USER_DICTIONARY_SETTINGS = "key_user_dictionary_settings"; 69 // false: on ICS or later 70 private static final boolean SHOW_INPUT_METHOD_SWITCHER_SETTINGS = false; 71 72 private static final String[] sSystemSettingNames = { 73 System.TEXT_AUTO_REPLACE, System.TEXT_AUTO_CAPS, System.TEXT_AUTO_PUNCTUATE, 74 }; 75 76 private static final String[] sHardKeyboardKeys = { 77 "auto_replace", "auto_caps", "auto_punctuate", 78 }; 79 80 private int mDefaultInputMethodSelectorVisibility = 0; 81 private ListPreference mShowInputMethodSelectorPref; 82 private PreferenceCategory mKeyboardSettingsCategory; 83 private PreferenceCategory mHardKeyboardCategory; 84 private PreferenceCategory mGameControllerCategory; 85 private Preference mLanguagePref; 86 private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = 87 new ArrayList<InputMethodPreference>(); 88 private final ArrayList<PreferenceScreen> mHardKeyboardPreferenceList = 89 new ArrayList<PreferenceScreen>(); 90 private InputManager mIm; 91 private InputMethodManager mImm; 92 private boolean mIsOnlyImeSettings; 93 private Handler mHandler; 94 private SettingsObserver mSettingsObserver; 95 private Intent mIntentWaitingForResult; 96 private InputMethodSettingValuesWrapper mInputMethodSettingValues; 97 98 private final OnPreferenceChangeListener mOnImePreferenceChangedListener = 99 new OnPreferenceChangeListener() { 100 @Override 101 public boolean onPreferenceChange(Preference arg0, Object arg1) { 102 InputMethodSettingValuesWrapper.getInstance( 103 arg0.getContext()).refreshAllInputMethodAndSubtypes(); 104 ((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged(); 105 updateInputMethodPreferenceViews(); 106 return true; 107 } 108 }; 109 110 @Override 111 public void onCreate(Bundle icicle) { 112 super.onCreate(icicle); 113 114 addPreferencesFromResource(R.xml.language_settings); 115 116 try { 117 mDefaultInputMethodSelectorVisibility = Integer.valueOf( 118 getString(R.string.input_method_selector_visibility_default_value)); 119 } catch (NumberFormatException e) { 120 } 121 122 if (getActivity().getAssets().getLocales().length == 1) { 123 // No "Select language" pref if there's only one system locale available. 124 getPreferenceScreen().removePreference(findPreference(KEY_PHONE_LANGUAGE)); 125 } else { 126 mLanguagePref = findPreference(KEY_PHONE_LANGUAGE); 127 } 128 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 129 mShowInputMethodSelectorPref = (ListPreference)findPreference( 130 KEY_INPUT_METHOD_SELECTOR); 131 mShowInputMethodSelectorPref.setOnPreferenceChangeListener(this); 132 // TODO: Update current input method name on summary 133 updateInputMethodSelectorSummary(loadInputMethodSelectorVisibility()); 134 } 135 136 new VoiceInputOutputSettings(this).onCreate(); 137 138 // Get references to dynamically constructed categories. 139 mHardKeyboardCategory = (PreferenceCategory)findPreference("hard_keyboard"); 140 mKeyboardSettingsCategory = (PreferenceCategory)findPreference( 141 "keyboard_settings_category"); 142 mGameControllerCategory = (PreferenceCategory)findPreference( 143 "game_controller_settings_category"); 144 145 // Filter out irrelevant features if invoked from IME settings button. 146 mIsOnlyImeSettings = Settings.ACTION_INPUT_METHOD_SETTINGS.equals( 147 getActivity().getIntent().getAction()); 148 getActivity().getIntent().setAction(null); 149 if (mIsOnlyImeSettings) { 150 getPreferenceScreen().removeAll(); 151 getPreferenceScreen().addPreference(mHardKeyboardCategory); 152 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 153 getPreferenceScreen().addPreference(mShowInputMethodSelectorPref); 154 } 155 getPreferenceScreen().addPreference(mKeyboardSettingsCategory); 156 } 157 158 // Build IME preference category. 159 mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 160 mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(getActivity()); 161 162 mKeyboardSettingsCategory.removeAll(); 163 if (!mIsOnlyImeSettings) { 164 final PreferenceScreen currentIme = new PreferenceScreen(getActivity(), null); 165 currentIme.setKey(KEY_CURRENT_INPUT_METHOD); 166 currentIme.setTitle(getResources().getString(R.string.current_input_method)); 167 mKeyboardSettingsCategory.addPreference(currentIme); 168 } 169 170 // Build hard keyboard and game controller preference categories. 171 mIm = (InputManager)getActivity().getSystemService(Context.INPUT_SERVICE); 172 updateInputDevices(); 173 174 // Spell Checker 175 final Intent intent = new Intent(Intent.ACTION_MAIN); 176 intent.setClass(getActivity(), SpellCheckersSettingsActivity.class); 177 final SpellCheckersPreference scp = ((SpellCheckersPreference)findPreference( 178 "spellcheckers_settings")); 179 if (scp != null) { 180 scp.setFragmentIntent(this, intent); 181 } 182 183 mHandler = new Handler(); 184 mSettingsObserver = new SettingsObserver(mHandler, getActivity()); 185 } 186 187 private void updateInputMethodSelectorSummary(int value) { 188 String[] inputMethodSelectorTitles = getResources().getStringArray( 189 R.array.input_method_selector_titles); 190 if (inputMethodSelectorTitles.length > value) { 191 mShowInputMethodSelectorPref.setSummary(inputMethodSelectorTitles[value]); 192 mShowInputMethodSelectorPref.setValue(String.valueOf(value)); 193 } 194 } 195 196 private void updateUserDictionaryPreference(Preference userDictionaryPreference) { 197 final Activity activity = getActivity(); 198 final TreeSet<String> localeSet = UserDictionaryList.getUserDictionaryLocalesSet(activity); 199 if (null == localeSet) { 200 // The locale list is null if and only if the user dictionary service is 201 // not present or disabled. In this case we need to remove the preference. 202 getPreferenceScreen().removePreference(userDictionaryPreference); 203 } else { 204 userDictionaryPreference.setOnPreferenceClickListener( 205 new OnPreferenceClickListener() { 206 @Override 207 public boolean onPreferenceClick(Preference arg0) { 208 // Redirect to UserDictionarySettings if the user needs only one 209 // language. 210 final Bundle extras = new Bundle(); 211 final Class<? extends Fragment> targetFragment; 212 if (localeSet.size() <= 1) { 213 if (!localeSet.isEmpty()) { 214 // If the size of localeList is 0, we don't set the locale 215 // parameter in the extras. This will be interpreted by the 216 // UserDictionarySettings class as meaning 217 // "the current locale". Note that with the current code for 218 // UserDictionaryList#getUserDictionaryLocalesSet() 219 // the locale list always has at least one element, since it 220 // always includes the current locale explicitly. 221 // @see UserDictionaryList.getUserDictionaryLocalesSet(). 222 extras.putString("locale", localeSet.first()); 223 } 224 targetFragment = UserDictionarySettings.class; 225 } else { 226 targetFragment = UserDictionaryList.class; 227 } 228 startFragment(InputMethodAndLanguageSettings.this, 229 targetFragment.getCanonicalName(), -1, extras); 230 return true; 231 } 232 }); 233 } 234 } 235 236 @Override 237 public void onResume() { 238 super.onResume(); 239 240 mSettingsObserver.resume(); 241 mIm.registerInputDeviceListener(this, null); 242 243 if (!mIsOnlyImeSettings) { 244 if (mLanguagePref != null) { 245 Configuration conf = getResources().getConfiguration(); 246 String language = conf.locale.getLanguage(); 247 String localeString; 248 // TODO: This is not an accurate way to display the locale, as it is 249 // just working around the fact that we support limited dialects 250 // and want to pretend that the language is valid for all locales. 251 // We need a way to support languages that aren't tied to a particular 252 // locale instead of hiding the locale qualifier. 253 if (language.equals("zz")) { 254 String country = conf.locale.getCountry(); 255 if (country.equals("ZZ")) { 256 localeString = "[Developer] Accented English (zz_ZZ)"; 257 } else if (country.equals("ZY")) { 258 localeString = "[Developer] Fake Bi-Directional (zz_ZY)"; 259 } else { 260 localeString = ""; 261 } 262 } else if (hasOnlyOneLanguageInstance(language, 263 Resources.getSystem().getAssets().getLocales())) { 264 localeString = conf.locale.getDisplayLanguage(conf.locale); 265 } else { 266 localeString = conf.locale.getDisplayName(conf.locale); 267 } 268 if (localeString.length() > 1) { 269 localeString = Character.toUpperCase(localeString.charAt(0)) 270 + localeString.substring(1); 271 mLanguagePref.setSummary(localeString); 272 } 273 } 274 275 updateUserDictionaryPreference(findPreference(KEY_USER_DICTIONARY_SETTINGS)); 276 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 277 mShowInputMethodSelectorPref.setOnPreferenceChangeListener(this); 278 } 279 } 280 281 // Hard keyboard 282 if (!mHardKeyboardPreferenceList.isEmpty()) { 283 for (int i = 0; i < sHardKeyboardKeys.length; ++i) { 284 CheckBoxPreference chkPref = (CheckBoxPreference) 285 mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i]); 286 chkPref.setChecked( 287 System.getInt(getContentResolver(), sSystemSettingNames[i], 1) > 0); 288 } 289 } 290 291 updateInputDevices(); 292 293 // Refresh internal states in mInputMethodSettingValues to keep the latest 294 // "InputMethodInfo"s and "InputMethodSubtype"s 295 mInputMethodSettingValues.refreshAllInputMethodAndSubtypes(); 296 updateInputMethodPreferenceViews(); 297 } 298 299 @Override 300 public void onPause() { 301 super.onPause(); 302 303 mIm.unregisterInputDeviceListener(this); 304 mSettingsObserver.pause(); 305 306 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 307 mShowInputMethodSelectorPref.setOnPreferenceChangeListener(null); 308 } 309 // TODO: Consolidate the logic to InputMethodSettingsWrapper 310 InputMethodAndSubtypeUtil.saveInputMethodSubtypeList( 311 this, getContentResolver(), mInputMethodSettingValues.getInputMethodList(), 312 !mHardKeyboardPreferenceList.isEmpty()); 313 } 314 315 @Override 316 public void onInputDeviceAdded(int deviceId) { 317 updateInputDevices(); 318 } 319 320 @Override 321 public void onInputDeviceChanged(int deviceId) { 322 updateInputDevices(); 323 } 324 325 @Override 326 public void onInputDeviceRemoved(int deviceId) { 327 updateInputDevices(); 328 } 329 330 @Override 331 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 332 // Input Method stuff 333 if (Utils.isMonkeyRunning()) { 334 return false; 335 } 336 if (preference instanceof PreferenceScreen) { 337 if (preference.getFragment() != null) { 338 // Fragment will be handled correctly by the super class. 339 } else if (KEY_CURRENT_INPUT_METHOD.equals(preference.getKey())) { 340 final InputMethodManager imm = (InputMethodManager) 341 getSystemService(Context.INPUT_METHOD_SERVICE); 342 imm.showInputMethodPicker(); 343 } 344 } else if (preference instanceof CheckBoxPreference) { 345 final CheckBoxPreference chkPref = (CheckBoxPreference) preference; 346 if (!mHardKeyboardPreferenceList.isEmpty()) { 347 for (int i = 0; i < sHardKeyboardKeys.length; ++i) { 348 if (chkPref == mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i])) { 349 System.putInt(getContentResolver(), sSystemSettingNames[i], 350 chkPref.isChecked() ? 1 : 0); 351 return true; 352 } 353 } 354 } 355 if (chkPref == mGameControllerCategory.findPreference("vibrate_input_devices")) { 356 System.putInt(getContentResolver(), Settings.System.VIBRATE_INPUT_DEVICES, 357 chkPref.isChecked() ? 1 : 0); 358 return true; 359 } 360 } 361 return super.onPreferenceTreeClick(preferenceScreen, preference); 362 } 363 364 private boolean hasOnlyOneLanguageInstance(String languageCode, String[] locales) { 365 int count = 0; 366 for (String localeCode : locales) { 367 if (localeCode.length() > 2 368 && localeCode.startsWith(languageCode)) { 369 count++; 370 if (count > 1) { 371 return false; 372 } 373 } 374 } 375 return count == 1; 376 } 377 378 private void saveInputMethodSelectorVisibility(String value) { 379 try { 380 int intValue = Integer.valueOf(value); 381 Settings.Secure.putInt(getContentResolver(), 382 Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, intValue); 383 updateInputMethodSelectorSummary(intValue); 384 } catch(NumberFormatException e) { 385 } 386 } 387 388 private int loadInputMethodSelectorVisibility() { 389 return Settings.Secure.getInt(getContentResolver(), 390 Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY, 391 mDefaultInputMethodSelectorVisibility); 392 } 393 394 @Override 395 public boolean onPreferenceChange(Preference preference, Object value) { 396 if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) { 397 if (preference == mShowInputMethodSelectorPref) { 398 if (value instanceof String) { 399 saveInputMethodSelectorVisibility((String)value); 400 } 401 } 402 } 403 return false; 404 } 405 406 private void updateInputMethodPreferenceViews() { 407 synchronized (mInputMethodPreferenceList) { 408 // Clear existing "InputMethodPreference"s 409 for (final InputMethodPreference imp : mInputMethodPreferenceList) { 410 mKeyboardSettingsCategory.removePreference(imp); 411 } 412 mInputMethodPreferenceList.clear(); 413 final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList(); 414 final int N = (imis == null ? 0 : imis.size()); 415 for (int i = 0; i < N; ++i) { 416 final InputMethodInfo imi = imis.get(i); 417 final InputMethodPreference pref = getInputMethodPreference(imi); 418 pref.setOnImePreferenceChangeListener(mOnImePreferenceChangedListener); 419 mInputMethodPreferenceList.add(pref); 420 } 421 422 if (!mInputMethodPreferenceList.isEmpty()) { 423 Collections.sort(mInputMethodPreferenceList); 424 for (int i = 0; i < N; ++i) { 425 mKeyboardSettingsCategory.addPreference(mInputMethodPreferenceList.get(i)); 426 } 427 } 428 429 // update views status 430 for (Preference pref : mInputMethodPreferenceList) { 431 if (pref instanceof InputMethodPreference) { 432 ((InputMethodPreference) pref).updatePreferenceViews(); 433 } 434 } 435 } 436 updateCurrentImeName(); 437 // TODO: Consolidate the logic with InputMethodSettingsWrapper 438 // CAVEAT: The preference class here does not know about the default value - that is 439 // managed by the Input Method Manager Service, so in this case it could save the wrong 440 // value. Hence we must update the checkboxes here. 441 InputMethodAndSubtypeUtil.loadInputMethodSubtypeList( 442 this, getContentResolver(), 443 mInputMethodSettingValues.getInputMethodList(), null); 444 } 445 446 private void updateCurrentImeName() { 447 final Context context = getActivity(); 448 if (context == null || mImm == null) return; 449 final Preference curPref = getPreferenceScreen().findPreference(KEY_CURRENT_INPUT_METHOD); 450 if (curPref != null) { 451 final CharSequence curIme = 452 mInputMethodSettingValues.getCurrentInputMethodName(context); 453 if (!TextUtils.isEmpty(curIme)) { 454 synchronized(this) { 455 curPref.setSummary(curIme); 456 } 457 } 458 } 459 } 460 461 private InputMethodPreference getInputMethodPreference(InputMethodInfo imi) { 462 final PackageManager pm = getPackageManager(); 463 final CharSequence label = imi.loadLabel(pm); 464 // IME settings 465 final Intent intent; 466 final String settingsActivity = imi.getSettingsActivity(); 467 if (!TextUtils.isEmpty(settingsActivity)) { 468 intent = new Intent(Intent.ACTION_MAIN); 469 intent.setClassName(imi.getPackageName(), settingsActivity); 470 } else { 471 intent = null; 472 } 473 474 // Add a check box for enabling/disabling IME 475 final InputMethodPreference pref = 476 new InputMethodPreference(this, intent, mImm, imi); 477 pref.setKey(imi.getId()); 478 pref.setTitle(label); 479 return pref; 480 } 481 482 private void updateInputDevices() { 483 updateHardKeyboards(); 484 updateGameControllers(); 485 } 486 487 private void updateHardKeyboards() { 488 mHardKeyboardPreferenceList.clear(); 489 if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY) { 490 final int[] devices = InputDevice.getDeviceIds(); 491 for (int i = 0; i < devices.length; i++) { 492 InputDevice device = InputDevice.getDevice(devices[i]); 493 if (device != null 494 && !device.isVirtual() 495 && device.isFullKeyboard()) { 496 final InputDeviceIdentifier identifier = device.getIdentifier(); 497 final String keyboardLayoutDescriptor = 498 mIm.getCurrentKeyboardLayoutForInputDevice(identifier); 499 final KeyboardLayout keyboardLayout = keyboardLayoutDescriptor != null ? 500 mIm.getKeyboardLayout(keyboardLayoutDescriptor) : null; 501 502 final PreferenceScreen pref = new PreferenceScreen(getActivity(), null); 503 pref.setTitle(device.getName()); 504 if (keyboardLayout != null) { 505 pref.setSummary(keyboardLayout.toString()); 506 } else { 507 pref.setSummary(R.string.keyboard_layout_default_label); 508 } 509 pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 510 @Override 511 public boolean onPreferenceClick(Preference preference) { 512 showKeyboardLayoutDialog(identifier); 513 return true; 514 } 515 }); 516 mHardKeyboardPreferenceList.add(pref); 517 } 518 } 519 } 520 521 if (!mHardKeyboardPreferenceList.isEmpty()) { 522 for (int i = mHardKeyboardCategory.getPreferenceCount(); i-- > 0; ) { 523 final Preference pref = mHardKeyboardCategory.getPreference(i); 524 if (pref.getOrder() < 1000) { 525 mHardKeyboardCategory.removePreference(pref); 526 } 527 } 528 529 Collections.sort(mHardKeyboardPreferenceList); 530 final int count = mHardKeyboardPreferenceList.size(); 531 for (int i = 0; i < count; i++) { 532 final Preference pref = mHardKeyboardPreferenceList.get(i); 533 pref.setOrder(i); 534 mHardKeyboardCategory.addPreference(pref); 535 } 536 537 getPreferenceScreen().addPreference(mHardKeyboardCategory); 538 } else { 539 getPreferenceScreen().removePreference(mHardKeyboardCategory); 540 } 541 } 542 543 private void showKeyboardLayoutDialog(InputDeviceIdentifier inputDeviceIdentifier) { 544 KeyboardLayoutDialogFragment fragment = 545 new KeyboardLayoutDialogFragment(inputDeviceIdentifier); 546 fragment.setTargetFragment(this, 0); 547 fragment.show(getActivity().getFragmentManager(), "keyboardLayout"); 548 } 549 550 @Override 551 public void onSetupKeyboardLayouts(InputDeviceIdentifier inputDeviceIdentifier) { 552 final Intent intent = new Intent(Intent.ACTION_MAIN); 553 intent.setClass(getActivity(), KeyboardLayoutPickerActivity.class); 554 intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, 555 inputDeviceIdentifier); 556 mIntentWaitingForResult = intent; 557 startActivityForResult(intent, 0); 558 } 559 560 @Override 561 public void onActivityResult(int requestCode, int resultCode, Intent data) { 562 super.onActivityResult(requestCode, resultCode, data); 563 564 if (mIntentWaitingForResult != null) { 565 InputDeviceIdentifier inputDeviceIdentifier = mIntentWaitingForResult 566 .getParcelableExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER); 567 mIntentWaitingForResult = null; 568 showKeyboardLayoutDialog(inputDeviceIdentifier); 569 } 570 } 571 572 private void updateGameControllers() { 573 if (haveInputDeviceWithVibrator()) { 574 getPreferenceScreen().addPreference(mGameControllerCategory); 575 576 CheckBoxPreference chkPref = (CheckBoxPreference) 577 mGameControllerCategory.findPreference("vibrate_input_devices"); 578 chkPref.setChecked(System.getInt(getContentResolver(), 579 Settings.System.VIBRATE_INPUT_DEVICES, 1) > 0); 580 } else { 581 getPreferenceScreen().removePreference(mGameControllerCategory); 582 } 583 } 584 585 private boolean haveInputDeviceWithVibrator() { 586 final int[] devices = InputDevice.getDeviceIds(); 587 for (int i = 0; i < devices.length; i++) { 588 InputDevice device = InputDevice.getDevice(devices[i]); 589 if (device != null && !device.isVirtual() && device.getVibrator().hasVibrator()) { 590 return true; 591 } 592 } 593 return false; 594 } 595 596 private class SettingsObserver extends ContentObserver { 597 private Context mContext; 598 599 public SettingsObserver(Handler handler, Context context) { 600 super(handler); 601 mContext = context; 602 } 603 604 @Override public void onChange(boolean selfChange) { 605 updateCurrentImeName(); 606 } 607 608 public void resume() { 609 final ContentResolver cr = mContext.getContentResolver(); 610 cr.registerContentObserver( 611 Settings.Secure.getUriFor(Settings.Secure.DEFAULT_INPUT_METHOD), false, this); 612 cr.registerContentObserver(Settings.Secure.getUriFor( 613 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this); 614 } 615 616 public void pause() { 617 mContext.getContentResolver().unregisterContentObserver(this); 618 } 619 } 620} 621