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 }