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