• 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"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.inputmethod.latin;
18 
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.app.Fragment;
23 import android.app.backup.BackupManager;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.SharedPreferences;
28 import android.content.res.Resources;
29 import android.os.Bundle;
30 import android.preference.CheckBoxPreference;
31 import android.preference.ListPreference;
32 import android.preference.Preference;
33 import android.preference.Preference.OnPreferenceClickListener;
34 import android.preference.PreferenceGroup;
35 import android.preference.PreferenceScreen;
36 import android.text.TextUtils;
37 import android.text.method.LinkMovementMethod;
38 import android.util.Log;
39 import android.view.View;
40 import android.view.inputmethod.EditorInfo;
41 import android.widget.SeekBar;
42 import android.widget.SeekBar.OnSeekBarChangeListener;
43 import android.widget.TextView;
44 
45 import com.android.inputmethod.compat.CompatUtils;
46 import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
47 import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
48 import com.android.inputmethod.compat.InputTypeCompatUtils;
49 import com.android.inputmethod.compat.VibratorCompatWrapper;
50 import com.android.inputmethod.deprecated.VoiceProxy;
51 import com.android.inputmethodcommon.InputMethodSettingsActivity;
52 
53 import java.util.Arrays;
54 import java.util.Locale;
55 
56 public class Settings extends InputMethodSettingsActivity
57         implements SharedPreferences.OnSharedPreferenceChangeListener,
58         DialogInterface.OnDismissListener, OnPreferenceClickListener {
59     private static final String TAG = Settings.class.getSimpleName();
60 
61     public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false;
62 
63     public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings";
64     public static final String PREF_VIBRATE_ON = "vibrate_on";
65     public static final String PREF_SOUND_ON = "sound_on";
66     public static final String PREF_KEY_PREVIEW_POPUP_ON = "popup_on";
67     public static final String PREF_AUTO_CAP = "auto_cap";
68     public static final String PREF_SHOW_SETTINGS_KEY = "show_settings_key";
69     public static final String PREF_VOICE_SETTINGS_KEY = "voice_mode";
70     public static final String PREF_INPUT_LANGUAGE = "input_language";
71     public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
72     public static final String PREF_SUBTYPES = "subtype_settings";
73 
74     public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key";
75     public static final String PREF_CORRECTION_SETTINGS_KEY = "correction_settings";
76     public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting";
77     public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
78     public static final String PREF_DEBUG_SETTINGS = "debug_settings";
79 
80     public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
81     public static final String PREF_BIGRAM_PREDICTIONS = "bigram_prediction";
82 
83     public static final String PREF_MISC_SETTINGS_KEY = "misc_settings";
84 
85     public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY =
86             "pref_key_preview_popup_dismiss_delay";
87     public static final String PREF_KEY_USE_CONTACTS_DICT =
88             "pref_key_use_contacts_dict";
89     public static final String PREF_KEY_ENABLE_SPAN_INSERT =
90             "enable_span_insert";
91 
92     public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
93 
94     public static final String PREF_VIBRATION_DURATION_SETTINGS =
95             "pref_vibration_duration_settings";
96 
97     // Dialog ids
98     private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
99 
100     public static class Values {
101         // From resources:
102         public final int mDelayBeforeFadeoutLanguageOnSpacebar;
103         public final int mDelayUpdateSuggestions;
104         public final int mDelayUpdateOldSuggestions;
105         public final int mDelayUpdateShiftState;
106         public final int mDurationOfFadeoutLanguageOnSpacebar;
107         public final float mFinalFadeoutFactorOfLanguageOnSpacebar;
108         public final long mDoubleSpacesTurnIntoPeriodTimeout;
109         public final String mWordSeparators;
110         public final String mMagicSpaceStrippers;
111         public final String mMagicSpaceSwappers;
112         public final String mSuggestPuncs;
113         public final SuggestedWords mSuggestPuncList;
114         private final String mSymbolsExcludedFromWordSeparators;
115 
116         // From preferences:
117         public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn)
118         public final boolean mVibrateOn;
119         public final boolean mKeyPreviewPopupOn;
120         public final int mKeyPreviewPopupDismissDelay;
121         public final boolean mAutoCap;
122         public final boolean mAutoCorrectEnabled;
123         public final double mAutoCorrectionThreshold;
124         // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
125         public final boolean mBigramSuggestionEnabled;
126         // Prediction: use bigrams to predict the next word when there is no input for it yet
127         public final boolean mBigramPredictionEnabled;
128         public final boolean mUseContactsDict;
129         public final boolean mEnableSuggestionSpanInsertion;
130 
131         private final boolean mShowSettingsKey;
132         private final boolean mVoiceKeyEnabled;
133         private final boolean mVoiceKeyOnMain;
134 
Values(final SharedPreferences prefs, final Context context, final String localeStr)135         public Values(final SharedPreferences prefs, final Context context,
136                 final String localeStr) {
137             final Resources res = context.getResources();
138             final Locale savedLocale;
139             if (null != localeStr) {
140                 final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
141                 savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
142             } else {
143                 savedLocale = null;
144             }
145 
146             // Get the resources
147             mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
148                     R.integer.config_delay_before_fadeout_language_on_spacebar);
149             mDelayUpdateSuggestions =
150                     res.getInteger(R.integer.config_delay_update_suggestions);
151             mDelayUpdateOldSuggestions = res.getInteger(
152                     R.integer.config_delay_update_old_suggestions);
153             mDelayUpdateShiftState =
154                     res.getInteger(R.integer.config_delay_update_shift_state);
155             mDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
156                     R.integer.config_duration_of_fadeout_language_on_spacebar);
157             mFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
158                     R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
159             mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger(
160                     R.integer.config_double_spaces_turn_into_period_timeout);
161             mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
162             mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
163             String wordSeparators = mMagicSpaceStrippers + mMagicSpaceSwappers
164                     + res.getString(R.string.magic_space_promoting_symbols);
165             final String symbolsExcludedFromWordSeparators =
166                     res.getString(R.string.symbols_excluded_from_word_separators);
167             for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
168                 wordSeparators = wordSeparators.replace(
169                         symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
170             }
171             mSymbolsExcludedFromWordSeparators = symbolsExcludedFromWordSeparators;
172             mWordSeparators = wordSeparators;
173             mSuggestPuncs = res.getString(R.string.suggested_punctuations);
174             // TODO: it would be nice not to recreate this each time we change the configuration
175             mSuggestPuncList = createSuggestPuncList(mSuggestPuncs);
176 
177             // Get the settings preferences
178             final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator();
179             mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON,
180                     res.getBoolean(R.bool.config_default_vibration_enabled));
181             mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
182                     res.getBoolean(R.bool.config_default_sound_enabled));
183             mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res);
184             mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res);
185             mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
186             mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res);
187             mBigramSuggestionEnabled = mAutoCorrectEnabled
188                     && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
189             mBigramPredictionEnabled = mBigramSuggestionEnabled
190                     && isBigramPredictionEnabled(prefs, res);
191             mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res);
192             mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
193             mEnableSuggestionSpanInsertion =
194                     prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
195             final boolean defaultShowSettingsKey = res.getBoolean(
196                     R.bool.config_default_show_settings_key);
197             mShowSettingsKey = isShowSettingsKeyOption(res)
198                     ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey)
199                     : defaultShowSettingsKey;
200             final String voiceModeMain = res.getString(R.string.voice_mode_main);
201             final String voiceModeOff = res.getString(R.string.voice_mode_off);
202             final String voiceMode = prefs.getString(PREF_VOICE_SETTINGS_KEY, voiceModeMain);
203             mVoiceKeyEnabled = voiceMode != null && !voiceMode.equals(voiceModeOff);
204             mVoiceKeyOnMain = voiceMode != null && voiceMode.equals(voiceModeMain);
205 
206             LocaleUtils.setSystemLocale(res, savedLocale);
207         }
208 
isSuggestedPunctuation(int code)209         public boolean isSuggestedPunctuation(int code) {
210             return mSuggestPuncs.contains(String.valueOf((char)code));
211         }
212 
isWordSeparator(int code)213         public boolean isWordSeparator(int code) {
214             return mWordSeparators.contains(String.valueOf((char)code));
215         }
216 
isSymbolExcludedFromWordSeparators(int code)217         public boolean isSymbolExcludedFromWordSeparators(int code) {
218             return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
219         }
220 
isMagicSpaceStripper(int code)221         public boolean isMagicSpaceStripper(int code) {
222             return mMagicSpaceStrippers.contains(String.valueOf((char)code));
223         }
224 
isMagicSpaceSwapper(int code)225         public boolean isMagicSpaceSwapper(int code) {
226             return mMagicSpaceSwappers.contains(String.valueOf((char)code));
227         }
228 
isAutoCorrectEnabled(SharedPreferences sp, Resources resources)229         private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) {
230             final String currentAutoCorrectionSetting = sp.getString(
231                     Settings.PREF_AUTO_CORRECTION_THRESHOLD,
232                     resources.getString(R.string.auto_correction_threshold_mode_index_modest));
233             final String autoCorrectionOff = resources.getString(
234                     R.string.auto_correction_threshold_mode_index_off);
235             return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
236         }
237 
238         // Public to access from KeyboardSwitcher. Should it have access to some
239         // process-global instance instead?
isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources)240         public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) {
241             final boolean showPopupOption = resources.getBoolean(
242                     R.bool.config_enable_show_popup_on_keypress_option);
243             if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview);
244             return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON,
245                     resources.getBoolean(R.bool.config_default_popup_preview));
246         }
247 
248         // Likewise
getKeyPreviewPopupDismissDelay(SharedPreferences sp, Resources resources)249         public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp,
250                 Resources resources) {
251             return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
252                     Integer.toString(resources.getInteger(R.integer.config_delay_after_preview))));
253         }
254 
isBigramSuggestionEnabled(SharedPreferences sp, Resources resources, boolean autoCorrectEnabled)255         private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources,
256                 boolean autoCorrectEnabled) {
257             final boolean showBigramSuggestionsOption = resources.getBoolean(
258                     R.bool.config_enable_bigram_suggestions_option);
259             if (!showBigramSuggestionsOption) {
260                 return autoCorrectEnabled;
261             }
262             return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean(
263                     R.bool.config_default_bigram_suggestions));
264         }
265 
isBigramPredictionEnabled(SharedPreferences sp, Resources resources)266         private static boolean isBigramPredictionEnabled(SharedPreferences sp,
267                 Resources resources) {
268             return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean(
269                     R.bool.config_default_bigram_prediction));
270         }
271 
getAutoCorrectionThreshold(SharedPreferences sp, Resources resources)272         private static double getAutoCorrectionThreshold(SharedPreferences sp,
273                 Resources resources) {
274             final String currentAutoCorrectionSetting = sp.getString(
275                     Settings.PREF_AUTO_CORRECTION_THRESHOLD,
276                     resources.getString(R.string.auto_correction_threshold_mode_index_modest));
277             final String[] autoCorrectionThresholdValues = resources.getStringArray(
278                     R.array.auto_correction_threshold_values);
279             // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
280             double autoCorrectionThreshold = Double.MAX_VALUE;
281             try {
282                 final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
283                 if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
284                     autoCorrectionThreshold = Double.parseDouble(
285                             autoCorrectionThresholdValues[arrayIndex]);
286                 }
287             } catch (NumberFormatException e) {
288                 // Whenever the threshold settings are correct, never come here.
289                 autoCorrectionThreshold = Double.MAX_VALUE;
290                 Log.w(TAG, "Cannot load auto correction threshold setting."
291                         + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
292                         + ", autoCorrectionThresholdValues: "
293                         + Arrays.toString(autoCorrectionThresholdValues));
294             }
295             return autoCorrectionThreshold;
296         }
297 
createSuggestPuncList(final String puncs)298         private static SuggestedWords createSuggestPuncList(final String puncs) {
299             SuggestedWords.Builder builder = new SuggestedWords.Builder();
300             if (puncs != null) {
301                 for (int i = 0; i < puncs.length(); i++) {
302                     builder.addWord(puncs.subSequence(i, i + 1));
303                 }
304             }
305             return builder.setIsPunctuationSuggestions().build();
306         }
307 
isShowSettingsKeyOption(final Resources resources)308         public static boolean isShowSettingsKeyOption(final Resources resources) {
309             return resources.getBoolean(R.bool.config_enable_show_settings_key_option);
310 
311         }
312 
isSettingsKeyEnabled()313         public boolean isSettingsKeyEnabled() {
314             return mShowSettingsKey;
315         }
316 
isVoiceKeyEnabled(EditorInfo attribute)317         public boolean isVoiceKeyEnabled(EditorInfo attribute) {
318             final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
319             final int inputType = (attribute != null) ? attribute.inputType : 0;
320             return shortcutImeEnabled && mVoiceKeyEnabled
321                     && !InputTypeCompatUtils.isPasswordInputType(inputType);
322         }
323 
isVoiceKeyOnMain()324         public boolean isVoiceKeyOnMain() {
325             return mVoiceKeyOnMain;
326         }
327     }
328 
329     private PreferenceScreen mInputLanguageSelection;
330     private PreferenceScreen mVibrationDurationSettingsPref;
331     private ListPreference mVoicePreference;
332     private CheckBoxPreference mShowSettingsKeyPreference;
333     private ListPreference mShowCorrectionSuggestionsPreference;
334     private ListPreference mAutoCorrectionThresholdPreference;
335     private ListPreference mKeyPreviewPopupDismissDelay;
336     // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
337     private CheckBoxPreference mBigramSuggestion;
338     // Prediction: use bigrams to predict the next word when there is no input for it yet
339     private CheckBoxPreference mBigramPrediction;
340     private Preference mDebugSettingsPreference;
341     private boolean mVoiceOn;
342 
343     private AlertDialog mDialog;
344     private TextView mVibrationSettingsTextView;
345 
346     private boolean mOkClicked = false;
347     private String mVoiceModeOff;
348 
ensureConsistencyOfAutoCorrectionSettings()349     private void ensureConsistencyOfAutoCorrectionSettings() {
350         final String autoCorrectionOff = getResources().getString(
351                 R.string.auto_correction_threshold_mode_index_off);
352         final String currentSetting = mAutoCorrectionThresholdPreference.getValue();
353         mBigramSuggestion.setEnabled(!currentSetting.equals(autoCorrectionOff));
354         if (null != mBigramPrediction) {
355             mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff));
356         }
357     }
358 
getActivityInternal()359     public Activity getActivityInternal() {
360         Object thisObject = (Object) this;
361         if (thisObject instanceof Activity) {
362             return (Activity) thisObject;
363         } else if (thisObject instanceof Fragment) {
364             return ((Fragment) thisObject).getActivity();
365         } else {
366             return null;
367         }
368     }
369 
370     @Override
onCreate(Bundle icicle)371     public void onCreate(Bundle icicle) {
372         super.onCreate(icicle);
373         setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
374         setSubtypeEnablerTitle(R.string.select_language);
375         final Resources res = getResources();
376         final Context context = getActivityInternal();
377 
378         addPreferencesFromResource(R.xml.prefs);
379         mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES);
380         mInputLanguageSelection.setOnPreferenceClickListener(this);
381         mVoicePreference = (ListPreference) findPreference(PREF_VOICE_SETTINGS_KEY);
382         mShowSettingsKeyPreference = (CheckBoxPreference) findPreference(PREF_SHOW_SETTINGS_KEY);
383         mShowCorrectionSuggestionsPreference =
384                 (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING);
385         SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
386         prefs.registerOnSharedPreferenceChangeListener(this);
387 
388         mVoiceModeOff = getString(R.string.voice_mode_off);
389         mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
390                 .equals(mVoiceModeOff));
391 
392         mAutoCorrectionThresholdPreference =
393                 (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD);
394         mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
395         mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS);
396         mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS);
397         if (mDebugSettingsPreference != null) {
398             final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN);
399             debugSettingsIntent.setClassName(
400                     context.getPackageName(), DebugSettings.class.getName());
401             mDebugSettingsPreference.setIntent(debugSettingsIntent);
402         }
403 
404         ensureConsistencyOfAutoCorrectionSettings();
405 
406         final PreferenceGroup generalSettings =
407                 (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY);
408         final PreferenceGroup textCorrectionGroup =
409                 (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS_KEY);
410         final PreferenceGroup miscSettings =
411                 (PreferenceGroup) findPreference(PREF_MISC_SETTINGS_KEY);
412 
413         if (!Values.isShowSettingsKeyOption(res)) {
414             generalSettings.removePreference(mShowSettingsKeyPreference);
415         }
416 
417         final boolean showVoiceKeyOption = res.getBoolean(
418                 R.bool.config_enable_show_voice_key_option);
419         if (!showVoiceKeyOption) {
420             generalSettings.removePreference(mVoicePreference);
421         }
422 
423         if (!VibratorCompatWrapper.getInstance(context).hasVibrator()) {
424             generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
425         }
426 
427         if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
428             generalSettings.removePreference(findPreference(PREF_SUBTYPES));
429         }
430 
431         final boolean showPopupOption = res.getBoolean(
432                 R.bool.config_enable_show_popup_on_keypress_option);
433         if (!showPopupOption) {
434             generalSettings.removePreference(findPreference(PREF_KEY_PREVIEW_POPUP_ON));
435         }
436 
437         final boolean showBigramSuggestionsOption = res.getBoolean(
438                 R.bool.config_enable_bigram_suggestions_option);
439         if (!showBigramSuggestionsOption) {
440             textCorrectionGroup.removePreference(mBigramSuggestion);
441             if (null != mBigramPrediction) {
442                 textCorrectionGroup.removePreference(mBigramPrediction);
443             }
444         }
445 
446         mKeyPreviewPopupDismissDelay =
447                 (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
448         final String[] entries = new String[] {
449                 res.getString(R.string.key_preview_popup_dismiss_no_delay),
450                 res.getString(R.string.key_preview_popup_dismiss_default_delay),
451         };
452         final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
453                 R.integer.config_delay_after_preview));
454         mKeyPreviewPopupDismissDelay.setEntries(entries);
455         mKeyPreviewPopupDismissDelay.setEntryValues(
456                 new String[] { "0", popupDismissDelayDefaultValue });
457         if (null == mKeyPreviewPopupDismissDelay.getValue()) {
458             mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
459         }
460         mKeyPreviewPopupDismissDelay.setEnabled(Values.isKeyPreviewPopupEnabled(prefs, res));
461 
462         final PreferenceScreen dictionaryLink =
463                 (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY);
464         final Intent intent = dictionaryLink.getIntent();
465 
466         final int number = context.getPackageManager().queryIntentActivities(intent, 0).size();
467         if (0 >= number) {
468             textCorrectionGroup.removePreference(dictionaryLink);
469         }
470 
471         final boolean showUsabilityModeStudyOption = res.getBoolean(
472                 R.bool.config_enable_usability_study_mode_option);
473         if (!showUsabilityModeStudyOption || !ENABLE_EXPERIMENTAL_SETTINGS) {
474             final Preference pref = findPreference(PREF_USABILITY_STUDY_MODE);
475             if (pref != null) {
476                 miscSettings.removePreference(pref);
477             }
478         }
479 
480         mVibrationDurationSettingsPref =
481                 (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS);
482         if (mVibrationDurationSettingsPref != null) {
483             mVibrationDurationSettingsPref.setOnPreferenceClickListener(
484                     new OnPreferenceClickListener() {
485                         @Override
486                         public boolean onPreferenceClick(Preference arg0) {
487                             showVibrationSettingsDialog();
488                             return true;
489                         }
490                     });
491             updateVibrationDurationSettingsSummary(prefs, res);
492         }
493     }
494 
495     @SuppressWarnings("unused")
496     @Override
onResume()497     public void onResume() {
498         super.onResume();
499         final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
500         if (isShortcutImeEnabled
501                 || (VoiceProxy.VOICE_INSTALLED
502                         && VoiceProxy.isRecognitionAvailable(getActivityInternal()))) {
503             updateVoiceModeSummary();
504         } else {
505             getPreferenceScreen().removePreference(mVoicePreference);
506         }
507         updateShowCorrectionSuggestionsSummary();
508         updateKeyPreviewPopupDelaySummary();
509     }
510 
511     @Override
onDestroy()512     public void onDestroy() {
513         getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
514                 this);
515         super.onDestroy();
516     }
517 
518     @Override
onSharedPreferenceChanged(SharedPreferences prefs, String key)519     public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
520         (new BackupManager(getActivityInternal())).dataChanged();
521         // If turning on voice input, show dialog
522         if (key.equals(PREF_VOICE_SETTINGS_KEY) && !mVoiceOn) {
523             if (!prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
524                     .equals(mVoiceModeOff)) {
525                 showVoiceConfirmation();
526             }
527         } else if (key.equals(PREF_KEY_PREVIEW_POPUP_ON)) {
528             final ListPreference popupDismissDelay =
529                 (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
530             if (null != popupDismissDelay) {
531                 popupDismissDelay.setEnabled(prefs.getBoolean(PREF_KEY_PREVIEW_POPUP_ON, true));
532             }
533         }
534         ensureConsistencyOfAutoCorrectionSettings();
535         mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
536                 .equals(mVoiceModeOff));
537         updateVoiceModeSummary();
538         updateShowCorrectionSuggestionsSummary();
539         updateKeyPreviewPopupDelaySummary();
540     }
541 
542     @Override
onPreferenceClick(Preference pref)543     public boolean onPreferenceClick(Preference pref) {
544         if (pref == mInputLanguageSelection) {
545             startActivity(CompatUtils.getInputLanguageSelectionIntent(
546                     Utils.getInputMethodId(
547                             InputMethodManagerCompatWrapper.getInstance(),
548                             getActivityInternal().getApplicationInfo().packageName), 0));
549             return true;
550         }
551         return false;
552     }
553 
updateShowCorrectionSuggestionsSummary()554     private void updateShowCorrectionSuggestionsSummary() {
555         mShowCorrectionSuggestionsPreference.setSummary(
556                 getResources().getStringArray(R.array.prefs_suggestion_visibilities)
557                 [mShowCorrectionSuggestionsPreference.findIndexOfValue(
558                         mShowCorrectionSuggestionsPreference.getValue())]);
559     }
560 
updateKeyPreviewPopupDelaySummary()561     private void updateKeyPreviewPopupDelaySummary() {
562         final ListPreference lp = mKeyPreviewPopupDismissDelay;
563         lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]);
564     }
565 
showVoiceConfirmation()566     private void showVoiceConfirmation() {
567         mOkClicked = false;
568         getActivityInternal().showDialog(VOICE_INPUT_CONFIRM_DIALOG);
569         // Make URL in the dialog message clickable
570         if (mDialog != null) {
571             TextView textView = (TextView) mDialog.findViewById(android.R.id.message);
572             if (textView != null) {
573                 textView.setMovementMethod(LinkMovementMethod.getInstance());
574             }
575         }
576     }
577 
updateVoiceModeSummary()578     private void updateVoiceModeSummary() {
579         mVoicePreference.setSummary(
580                 getResources().getStringArray(R.array.voice_input_modes_summary)
581                 [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]);
582     }
583 
584     @Override
onCreateDialog(int id)585     protected Dialog onCreateDialog(int id) {
586         switch (id) {
587             case VOICE_INPUT_CONFIRM_DIALOG:
588                 DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
589                     @Override
590                     public void onClick(DialogInterface dialog, int whichButton) {
591                         if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
592                             mVoicePreference.setValue(mVoiceModeOff);
593                         } else if (whichButton == DialogInterface.BUTTON_POSITIVE) {
594                             mOkClicked = true;
595                         }
596                     }
597                 };
598                 AlertDialog.Builder builder = new AlertDialog.Builder(getActivityInternal())
599                         .setTitle(R.string.voice_warning_title)
600                         .setPositiveButton(android.R.string.ok, listener)
601                         .setNegativeButton(android.R.string.cancel, listener);
602 
603                 // Get the current list of supported locales and check the current locale against
604                 // that list, to decide whether to put a warning that voice input will not work in
605                 // the current language as part of the pop-up confirmation dialog.
606                 boolean localeSupported = SubtypeSwitcher.isVoiceSupported(
607                         this, Locale.getDefault().toString());
608 
609                 final CharSequence message;
610                 if (localeSupported) {
611                     message = TextUtils.concat(
612                             getText(R.string.voice_warning_may_not_understand), "\n\n",
613                                     getText(R.string.voice_hint_dialog_message));
614                 } else {
615                     message = TextUtils.concat(
616                             getText(R.string.voice_warning_locale_not_supported), "\n\n",
617                                     getText(R.string.voice_warning_may_not_understand), "\n\n",
618                                             getText(R.string.voice_hint_dialog_message));
619                 }
620                 builder.setMessage(message);
621                 AlertDialog dialog = builder.create();
622                 mDialog = dialog;
623                 dialog.setOnDismissListener(this);
624                 return dialog;
625             default:
626                 Log.e(TAG, "unknown dialog " + id);
627                 return null;
628         }
629     }
630 
631     @Override
onDismiss(DialogInterface dialog)632     public void onDismiss(DialogInterface dialog) {
633         if (!mOkClicked) {
634             // This assumes that onPreferenceClick gets called first, and this if the user
635             // agreed after the warning, we set the mOkClicked value to true.
636             mVoicePreference.setValue(mVoiceModeOff);
637         }
638     }
639 
updateVibrationDurationSettingsSummary(SharedPreferences sp, Resources res)640     private void updateVibrationDurationSettingsSummary(SharedPreferences sp, Resources res) {
641         if (mVibrationDurationSettingsPref != null) {
642             mVibrationDurationSettingsPref.setSummary(
643                     Utils.getCurrentVibrationDuration(sp, res)
644                             + res.getString(R.string.settings_ms));
645         }
646     }
647 
showVibrationSettingsDialog()648     private void showVibrationSettingsDialog() {
649         final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
650         final Activity context = getActivityInternal();
651         final Resources res = context.getResources();
652         final AlertDialog.Builder builder = new AlertDialog.Builder(context);
653         builder.setTitle(R.string.prefs_vibration_duration_settings);
654         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
655             @Override
656             public void onClick(DialogInterface dialog, int whichButton) {
657                 final int ms = Integer.valueOf(mVibrationSettingsTextView.getText().toString());
658                 sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
659                 updateVibrationDurationSettingsSummary(sp, res);
660             }
661         });
662         builder.setNegativeButton(android.R.string.cancel,  new DialogInterface.OnClickListener() {
663             @Override
664             public void onClick(DialogInterface dialog, int whichButton) {
665                 dialog.dismiss();
666             }
667         });
668         final View v = context.getLayoutInflater().inflate(
669                 R.layout.vibration_settings_dialog, null);
670         final int currentMs = Utils.getCurrentVibrationDuration(
671                 getPreferenceManager().getSharedPreferences(), getResources());
672         mVibrationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value);
673         final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings);
674         sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
675             @Override
676             public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
677                 final int tempMs = arg1;
678                 mVibrationSettingsTextView.setText(String.valueOf(tempMs));
679             }
680 
681             @Override
682             public void onStartTrackingTouch(SeekBar arg0) {
683             }
684 
685             @Override
686             public void onStopTrackingTouch(SeekBar arg0) {
687                 final int tempMs = arg0.getProgress();
688                 VibratorCompatWrapper.getInstance(context).vibrate(tempMs);
689             }
690         });
691         sb.setProgress(currentMs);
692         mVibrationSettingsTextView.setText(String.valueOf(currentMs));
693         builder.setView(v);
694         builder.create().show();
695     }
696 }