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