1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import android.app.Activity; 20 import android.app.backup.BackupManager; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.SharedPreferences; 24 import android.content.pm.PackageManager; 25 import android.content.pm.ResolveInfo; 26 import android.content.res.Resources; 27 import android.media.AudioManager; 28 import android.os.Bundle; 29 import android.preference.CheckBoxPreference; 30 import android.preference.ListPreference; 31 import android.preference.Preference; 32 import android.preference.Preference.OnPreferenceClickListener; 33 import android.preference.PreferenceGroup; 34 import android.preference.PreferenceScreen; 35 import android.view.inputmethod.InputMethodSubtype; 36 37 import java.util.TreeSet; 38 39 import com.android.inputmethod.dictionarypack.DictionarySettingsActivity; 40 import com.android.inputmethod.latin.define.ProductionFlag; 41 import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager; 42 import com.android.inputmethod.latin.userdictionary.UserDictionaryList; 43 import com.android.inputmethod.latin.userdictionary.UserDictionarySettings; 44 import com.android.inputmethodcommon.InputMethodSettingsFragment; 45 46 public final class SettingsFragment extends InputMethodSettingsFragment 47 implements SharedPreferences.OnSharedPreferenceChangeListener { 48 private static final boolean DBG_USE_INTERNAL_USER_DICTIONARY_SETTINGS = false; 49 50 private ListPreference mVoicePreference; 51 private ListPreference mShowCorrectionSuggestionsPreference; 52 private ListPreference mAutoCorrectionThresholdPreference; 53 private ListPreference mKeyPreviewPopupDismissDelay; 54 // Use bigrams to predict the next word when there is no input for it yet 55 private CheckBoxPreference mBigramPrediction; 56 setPreferenceEnabled(final String preferenceKey, final boolean enabled)57 private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { 58 final Preference preference = findPreference(preferenceKey); 59 if (preference != null) { 60 preference.setEnabled(enabled); 61 } 62 } 63 removePreference(final String preferenceKey, final PreferenceGroup parent)64 private static void removePreference(final String preferenceKey, final PreferenceGroup parent) { 65 if (parent == null) { 66 return; 67 } 68 final Preference preference = parent.findPreference(preferenceKey); 69 if (preference != null) { 70 parent.removePreference(preference); 71 } 72 } 73 74 @Override onCreate(final Bundle icicle)75 public void onCreate(final Bundle icicle) { 76 super.onCreate(icicle); 77 setInputMethodSettingsCategoryTitle(R.string.language_selection_title); 78 setSubtypeEnablerTitle(R.string.select_language); 79 addPreferencesFromResource(R.xml.prefs); 80 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 81 if (preferenceScreen != null) { 82 preferenceScreen.setTitle( 83 Utils.getAcitivityTitleResId(getActivity(), SettingsActivity.class)); 84 } 85 86 final Resources res = getResources(); 87 final Context context = getActivity(); 88 89 // When we are called from the Settings application but we are not already running, some 90 // singleton and utility classes may not have been initialized. We have to call 91 // initialization method of these classes here. See {@link LatinIME#onCreate()}. 92 SubtypeSwitcher.init(context); 93 SubtypeLocale.init(context); 94 AudioAndHapticFeedbackManager.init(context); 95 96 mVoicePreference = (ListPreference) findPreference(Settings.PREF_VOICE_MODE); 97 mShowCorrectionSuggestionsPreference = 98 (ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING); 99 final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); 100 prefs.registerOnSharedPreferenceChangeListener(this); 101 102 mAutoCorrectionThresholdPreference = 103 (ListPreference) findPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD); 104 mBigramPrediction = (CheckBoxPreference) findPreference(Settings.PREF_BIGRAM_PREDICTIONS); 105 ensureConsistencyOfAutoCorrectionSettings(); 106 107 final PreferenceGroup generalSettings = 108 (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); 109 final PreferenceGroup miscSettings = 110 (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); 111 112 final Preference debugSettings = findPreference(Settings.PREF_DEBUG_SETTINGS); 113 if (debugSettings != null) { 114 if (Settings.isInternal(prefs)) { 115 final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); 116 debugSettingsIntent.setClassName( 117 context.getPackageName(), DebugSettingsActivity.class.getName()); 118 debugSettings.setIntent(debugSettingsIntent); 119 } else { 120 miscSettings.removePreference(debugSettings); 121 } 122 } 123 124 final Preference feedbackSettings = findPreference(Settings.PREF_SEND_FEEDBACK); 125 final Preference aboutSettings = findPreference(Settings.PREF_ABOUT_KEYBOARD); 126 if (feedbackSettings != null) { 127 if (FeedbackUtils.isFeedbackFormSupported()) { 128 feedbackSettings.setOnPreferenceClickListener(new OnPreferenceClickListener() { 129 @Override 130 public boolean onPreferenceClick(final Preference pref) { 131 FeedbackUtils.showFeedbackForm(getActivity()); 132 return true; 133 } 134 }); 135 aboutSettings.setTitle(FeedbackUtils.getAboutKeyboardTitleResId()); 136 aboutSettings.setIntent(FeedbackUtils.getAboutKeyboardIntent(getActivity())); 137 } else { 138 miscSettings.removePreference(feedbackSettings); 139 miscSettings.removePreference(aboutSettings); 140 } 141 } 142 143 final boolean showVoiceKeyOption = res.getBoolean( 144 R.bool.config_enable_show_voice_key_option); 145 if (!showVoiceKeyOption) { 146 generalSettings.removePreference(mVoicePreference); 147 } 148 149 final PreferenceGroup advancedSettings = 150 (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); 151 if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { 152 removePreference(Settings.PREF_VIBRATE_ON, generalSettings); 153 removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedSettings); 154 } 155 156 mKeyPreviewPopupDismissDelay = 157 (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); 158 if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption(res)) { 159 removePreference(Settings.PREF_POPUP_ON, generalSettings); 160 removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedSettings); 161 } else { 162 final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( 163 R.integer.config_key_preview_linger_timeout)); 164 mKeyPreviewPopupDismissDelay.setEntries(new String[] { 165 res.getString(R.string.key_preview_popup_dismiss_no_delay), 166 res.getString(R.string.key_preview_popup_dismiss_default_delay), 167 }); 168 mKeyPreviewPopupDismissDelay.setEntryValues(new String[] { 169 "0", 170 popupDismissDelayDefaultValue 171 }); 172 if (null == mKeyPreviewPopupDismissDelay.getValue()) { 173 mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); 174 } 175 mKeyPreviewPopupDismissDelay.setEnabled( 176 Settings.readKeyPreviewPopupEnabled(prefs, res)); 177 } 178 179 if (!res.getBoolean(R.bool.config_setup_wizard_available)) { 180 removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedSettings); 181 } 182 183 setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, 184 Settings.readShowsLanguageSwitchKey(prefs)); 185 186 final PreferenceGroup textCorrectionGroup = 187 (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); 188 final PreferenceScreen dictionaryLink = 189 (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); 190 final Intent intent = dictionaryLink.getIntent(); 191 intent.setClassName(context.getPackageName(), DictionarySettingsActivity.class.getName()); 192 final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); 193 // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack 194 // Service yet 195 if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS || 0 >= number) { 196 textCorrectionGroup.removePreference(dictionaryLink); 197 } 198 199 final Preference editPersonalDictionary = 200 findPreference(Settings.PREF_EDIT_PERSONAL_DICTIONARY); 201 final Intent editPersonalDictionaryIntent = editPersonalDictionary.getIntent(); 202 final ResolveInfo ri = context.getPackageManager().resolveActivity( 203 editPersonalDictionaryIntent, PackageManager.MATCH_DEFAULT_ONLY); 204 if (DBG_USE_INTERNAL_USER_DICTIONARY_SETTINGS || ri == null) { 205 updateUserDictionaryPreference(editPersonalDictionary); 206 } 207 208 if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) { 209 removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen()); 210 } 211 212 setupKeyLongpressTimeoutSettings(prefs, res); 213 setupKeypressVibrationDurationSettings(prefs, res); 214 setupKeypressSoundVolumeSettings(prefs, res); 215 refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); 216 } 217 218 @Override onResume()219 public void onResume() { 220 super.onResume(); 221 final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); 222 if (isShortcutImeEnabled) { 223 updateVoiceModeSummary(); 224 } else { 225 getPreferenceScreen().removePreference(mVoicePreference); 226 } 227 final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); 228 final CheckBoxPreference showSetupWizardIcon = 229 (CheckBoxPreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); 230 if (showSetupWizardIcon != null) { 231 showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity())); 232 } 233 updateShowCorrectionSuggestionsSummary(); 234 updateKeyPreviewPopupDelaySummary(); 235 updateCustomInputStylesSummary(); 236 } 237 238 @Override onDestroy()239 public void onDestroy() { 240 getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( 241 this); 242 super.onDestroy(); 243 } 244 245 @Override onSharedPreferenceChanged(final SharedPreferences prefs, final String key)246 public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { 247 (new BackupManager(getActivity())).dataChanged(); 248 final Resources res = getResources(); 249 if (key.equals(Settings.PREF_POPUP_ON)) { 250 setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, 251 Settings.readKeyPreviewPopupEnabled(prefs, res)); 252 } else if (key.equals(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY)) { 253 setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, 254 Settings.readShowsLanguageSwitchKey(prefs)); 255 } else if (key.equals(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) { 256 LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity()); 257 } 258 ensureConsistencyOfAutoCorrectionSettings(); 259 updateVoiceModeSummary(); 260 updateShowCorrectionSuggestionsSummary(); 261 updateKeyPreviewPopupDelaySummary(); 262 refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); 263 } 264 ensureConsistencyOfAutoCorrectionSettings()265 private void ensureConsistencyOfAutoCorrectionSettings() { 266 final String autoCorrectionOff = getResources().getString( 267 R.string.auto_correction_threshold_mode_index_off); 268 final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); 269 mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); 270 } 271 updateShowCorrectionSuggestionsSummary()272 private void updateShowCorrectionSuggestionsSummary() { 273 mShowCorrectionSuggestionsPreference.setSummary( 274 getResources().getStringArray(R.array.prefs_suggestion_visibilities) 275 [mShowCorrectionSuggestionsPreference.findIndexOfValue( 276 mShowCorrectionSuggestionsPreference.getValue())]); 277 } 278 updateCustomInputStylesSummary()279 private void updateCustomInputStylesSummary() { 280 final PreferenceScreen customInputStyles = 281 (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES); 282 final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); 283 final Resources res = getResources(); 284 final String prefSubtype = Settings.readPrefAdditionalSubtypes(prefs, res); 285 final InputMethodSubtype[] subtypes = 286 AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); 287 final StringBuilder styles = new StringBuilder(); 288 for (final InputMethodSubtype subtype : subtypes) { 289 if (styles.length() > 0) styles.append(", "); 290 styles.append(SubtypeLocale.getSubtypeDisplayNameInSystemLocale(subtype)); 291 } 292 customInputStyles.setSummary(styles); 293 } 294 updateKeyPreviewPopupDelaySummary()295 private void updateKeyPreviewPopupDelaySummary() { 296 final ListPreference lp = mKeyPreviewPopupDismissDelay; 297 final CharSequence[] entries = lp.getEntries(); 298 if (entries == null || entries.length <= 0) return; 299 lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]); 300 } 301 updateVoiceModeSummary()302 private void updateVoiceModeSummary() { 303 mVoicePreference.setSummary( 304 getResources().getStringArray(R.array.voice_input_modes_summary) 305 [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); 306 } 307 refreshEnablingsOfKeypressSoundAndVibrationSettings( final SharedPreferences sp, final Resources res)308 private void refreshEnablingsOfKeypressSoundAndVibrationSettings( 309 final SharedPreferences sp, final Resources res) { 310 setPreferenceEnabled(Settings.PREF_VIBRATION_DURATION_SETTINGS, 311 Settings.readVibrationEnabled(sp, res)); 312 setPreferenceEnabled(Settings.PREF_KEYPRESS_SOUND_VOLUME, 313 Settings.readKeypressSoundEnabled(sp, res)); 314 } 315 setupKeypressVibrationDurationSettings(final SharedPreferences sp, final Resources res)316 private void setupKeypressVibrationDurationSettings(final SharedPreferences sp, 317 final Resources res) { 318 final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( 319 Settings.PREF_VIBRATION_DURATION_SETTINGS); 320 if (pref == null) { 321 return; 322 } 323 pref.setInterface(new SeekBarDialogPreference.ValueProxy() { 324 @Override 325 public void writeValue(final int value, final String key) { 326 sp.edit().putInt(key, value).apply(); 327 } 328 329 @Override 330 public int readValue(final String key) { 331 return Settings.readKeypressVibrationDuration(sp, res); 332 } 333 334 @Override 335 public int readDefaultValue(final String key) { 336 return Settings.readDefaultKeypressVibrationDuration(res); 337 } 338 339 @Override 340 public void feedbackValue(final int value) { 341 AudioAndHapticFeedbackManager.getInstance().vibrate(value); 342 } 343 }); 344 } 345 setupKeyLongpressTimeoutSettings(final SharedPreferences sp, final Resources res)346 private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp, 347 final Resources res) { 348 final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( 349 Settings.PREF_KEY_LONGPRESS_TIMEOUT); 350 if (pref == null) { 351 return; 352 } 353 pref.setInterface(new SeekBarDialogPreference.ValueProxy() { 354 @Override 355 public void writeValue(final int value, final String key) { 356 sp.edit().putInt(key, value).apply(); 357 } 358 359 @Override 360 public int readValue(final String key) { 361 return Settings.readKeyLongpressTimeout(sp, res); 362 } 363 364 @Override 365 public int readDefaultValue(final String key) { 366 return Settings.readDefaultKeyLongpressTimeout(res); 367 } 368 369 @Override 370 public void feedbackValue(final int value) {} 371 }); 372 } 373 setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res)374 private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) { 375 final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( 376 Settings.PREF_KEYPRESS_SOUND_VOLUME); 377 if (pref == null) { 378 return; 379 } 380 final AudioManager am = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE); 381 pref.setInterface(new SeekBarDialogPreference.ValueProxy() { 382 private static final float PERCENTAGE_FLOAT = 100.0f; 383 384 private float getValueFromPercentage(final int percentage) { 385 return percentage / PERCENTAGE_FLOAT; 386 } 387 388 private int getPercentageFromValue(final float floatValue) { 389 return (int)(floatValue * PERCENTAGE_FLOAT); 390 } 391 392 @Override 393 public void writeValue(final int value, final String key) { 394 sp.edit().putFloat(key, getValueFromPercentage(value)).apply(); 395 } 396 397 @Override 398 public int readValue(final String key) { 399 return getPercentageFromValue(Settings.readKeypressSoundVolume(sp, res)); 400 } 401 402 @Override 403 public int readDefaultValue(final String key) { 404 return getPercentageFromValue(Settings.readDefaultKeypressSoundVolume(res)); 405 } 406 407 @Override 408 public void feedbackValue(final int value) { 409 am.playSoundEffect( 410 AudioManager.FX_KEYPRESS_STANDARD, getValueFromPercentage(value)); 411 } 412 }); 413 } 414 updateUserDictionaryPreference(Preference userDictionaryPreference)415 private void updateUserDictionaryPreference(Preference userDictionaryPreference) { 416 final Activity activity = getActivity(); 417 final TreeSet<String> localeList = UserDictionaryList.getUserDictionaryLocalesSet(activity); 418 if (null == localeList) { 419 // The locale list is null if and only if the user dictionary service is 420 // not present or disabled. In this case we need to remove the preference. 421 getPreferenceScreen().removePreference(userDictionaryPreference); 422 } else if (localeList.size() <= 1) { 423 userDictionaryPreference.setFragment(UserDictionarySettings.class.getName()); 424 // If the size of localeList is 0, we don't set the locale parameter in the 425 // extras. This will be interpreted by the UserDictionarySettings class as 426 // meaning "the current locale". 427 // Note that with the current code for UserDictionaryList#getUserDictionaryLocalesSet() 428 // the locale list always has at least one element, since it always includes the current 429 // locale explicitly. @see UserDictionaryList.getUserDictionaryLocalesSet(). 430 if (localeList.size() == 1) { 431 final String locale = (String)localeList.toArray()[0]; 432 userDictionaryPreference.getExtras().putString("locale", locale); 433 } 434 } else { 435 userDictionaryPreference.setFragment(UserDictionaryList.class.getName()); 436 } 437 } 438 } 439