Home | History | Annotate | Download | only in latin
      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 
    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 
    209         public boolean isSuggestedPunctuation(int code) {
    210             return mSuggestPuncs.contains(String.valueOf((char)code));
    211         }
    212 
    213         public boolean isWordSeparator(int code) {
    214             return mWordSeparators.contains(String.valueOf((char)code));
    215         }
    216 
    217         public boolean isSymbolExcludedFromWordSeparators(int code) {
    218             return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
    219         }
    220 
    221         public boolean isMagicSpaceStripper(int code) {
    222             return mMagicSpaceStrippers.contains(String.valueOf((char)code));
    223         }
    224 
    225         public boolean isMagicSpaceSwapper(int code) {
    226             return mMagicSpaceSwappers.contains(String.valueOf((char)code));
    227         }
    228 
    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?
    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
    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 
    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 
    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 
    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 
    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 
    308         public static boolean isShowSettingsKeyOption(final Resources resources) {
    309             return resources.getBoolean(R.bool.config_enable_show_settings_key_option);
    310 
    311         }
    312 
    313         public boolean isSettingsKeyEnabled() {
    314             return mShowSettingsKey;
    315         }
    316 
    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 
    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 
    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 
    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
    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
    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
    512     public void onDestroy() {
    513         getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
    514                 this);
    515         super.onDestroy();
    516     }
    517 
    518     @Override
    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
    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 
    554     private void updateShowCorrectionSuggestionsSummary() {
    555         mShowCorrectionSuggestionsPreference.setSummary(
    556                 getResources().getStringArray(R.array.prefs_suggestion_visibilities)
    557                 [mShowCorrectionSuggestionsPreference.findIndexOfValue(
    558                         mShowCorrectionSuggestionsPreference.getValue())]);
    559     }
    560 
    561     private void updateKeyPreviewPopupDelaySummary() {
    562         final ListPreference lp = mKeyPreviewPopupDismissDelay;
    563         lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]);
    564     }
    565 
    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 
    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
    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
    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 
    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 
    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 }