• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.inputmethod.latin;
18 
19 import android.app.AlertDialog;
20 import android.app.backup.BackupManager;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.content.SharedPreferences;
25 import android.content.res.Resources;
26 import android.media.AudioManager;
27 import android.os.Bundle;
28 import android.preference.CheckBoxPreference;
29 import android.preference.ListPreference;
30 import android.preference.Preference;
31 import android.preference.Preference.OnPreferenceClickListener;
32 import android.preference.PreferenceGroup;
33 import android.preference.PreferenceScreen;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.inputmethod.InputMethodSubtype;
37 import android.widget.SeekBar;
38 import android.widget.SeekBar.OnSeekBarChangeListener;
39 import android.widget.TextView;
40 
41 import com.android.inputmethod.latin.define.ProductionFlag;
42 import com.android.inputmethodcommon.InputMethodSettingsFragment;
43 
44 public class Settings extends InputMethodSettingsFragment
45         implements SharedPreferences.OnSharedPreferenceChangeListener {
46     public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false;
47 
48     // In the same order as xml/prefs.xml
49     public static final String PREF_GENERAL_SETTINGS = "general_settings";
50     public static final String PREF_AUTO_CAP = "auto_cap";
51     public static final String PREF_VIBRATE_ON = "vibrate_on";
52     public static final String PREF_SOUND_ON = "sound_on";
53     public static final String PREF_POPUP_ON = "popup_on";
54     public static final String PREF_VOICE_MODE = "voice_mode";
55     public static final String PREF_CORRECTION_SETTINGS = "correction_settings";
56     public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key";
57     public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
58     public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting";
59     public static final String PREF_MISC_SETTINGS = "misc_settings";
60     public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
61     public static final String PREF_LAST_USER_DICTIONARY_WRITE_TIME =
62             "last_user_dictionary_write_time";
63     public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings";
64     public static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY =
65             "pref_suppress_language_switch_key";
66     public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST =
67             "pref_include_other_imes_in_language_switch_list";
68     public static final String PREF_CUSTOM_INPUT_STYLES = "custom_input_styles";
69     public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY =
70             "pref_key_preview_popup_dismiss_delay";
71     public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict";
72     public static final String PREF_BIGRAM_SUGGESTION = "next_word_suggestion";
73     public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction";
74     public static final String PREF_KEY_ENABLE_SPAN_INSERT = "enable_span_insert";
75     public static final String PREF_VIBRATION_DURATION_SETTINGS =
76             "pref_vibration_duration_settings";
77     public static final String PREF_KEYPRESS_SOUND_VOLUME =
78             "pref_keypress_sound_volume";
79 
80     public static final String PREF_INPUT_LANGUAGE = "input_language";
81     public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
82     public static final String PREF_DEBUG_SETTINGS = "debug_settings";
83 
84     private PreferenceScreen mKeypressVibrationDurationSettingsPref;
85     private PreferenceScreen mKeypressSoundVolumeSettingsPref;
86     private ListPreference mVoicePreference;
87     private ListPreference mShowCorrectionSuggestionsPreference;
88     private ListPreference mAutoCorrectionThresholdPreference;
89     private ListPreference mKeyPreviewPopupDismissDelay;
90     // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
91     private CheckBoxPreference mBigramSuggestion;
92     // Prediction: use bigrams to predict the next word when there is no input for it yet
93     private CheckBoxPreference mBigramPrediction;
94     private Preference mDebugSettingsPreference;
95 
96     private TextView mKeypressVibrationDurationSettingsTextView;
97     private TextView mKeypressSoundVolumeSettingsTextView;
98 
ensureConsistencyOfAutoCorrectionSettings()99     private void ensureConsistencyOfAutoCorrectionSettings() {
100         final String autoCorrectionOff = getResources().getString(
101                 R.string.auto_correction_threshold_mode_index_off);
102         final String currentSetting = mAutoCorrectionThresholdPreference.getValue();
103         mBigramSuggestion.setEnabled(!currentSetting.equals(autoCorrectionOff));
104         if (null != mBigramPrediction) {
105             mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff));
106         }
107     }
108 
109     @Override
onCreate(Bundle icicle)110     public void onCreate(Bundle icicle) {
111         super.onCreate(icicle);
112         setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
113         setSubtypeEnablerTitle(R.string.select_language);
114         addPreferencesFromResource(R.xml.prefs);
115 
116         final Resources res = getResources();
117         final Context context = getActivity();
118 
119         mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE);
120         mShowCorrectionSuggestionsPreference =
121                 (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING);
122         SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
123         prefs.registerOnSharedPreferenceChangeListener(this);
124 
125         mAutoCorrectionThresholdPreference =
126                 (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD);
127         mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTION);
128         mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS);
129         mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS);
130         if (mDebugSettingsPreference != null) {
131             final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN);
132             debugSettingsIntent.setClassName(
133                     context.getPackageName(), DebugSettings.class.getName());
134             mDebugSettingsPreference.setIntent(debugSettingsIntent);
135         }
136 
137         ensureConsistencyOfAutoCorrectionSettings();
138 
139         final PreferenceGroup generalSettings =
140                 (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS);
141         final PreferenceGroup textCorrectionGroup =
142                 (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS);
143         final PreferenceGroup miscSettings =
144                 (PreferenceGroup) findPreference(PREF_MISC_SETTINGS);
145 
146         final boolean showVoiceKeyOption = res.getBoolean(
147                 R.bool.config_enable_show_voice_key_option);
148         if (!showVoiceKeyOption) {
149             generalSettings.removePreference(mVoicePreference);
150         }
151 
152         final PreferenceGroup advancedSettings =
153                 (PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS);
154         // Remove those meaningless options for now. TODO: delete them for good
155         advancedSettings.removePreference(findPreference(PREF_BIGRAM_SUGGESTION));
156         advancedSettings.removePreference(findPreference(PREF_KEY_ENABLE_SPAN_INSERT));
157         if (!VibratorUtils.getInstance(context).hasVibrator()) {
158             generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
159             if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
160                 advancedSettings.removePreference(findPreference(PREF_VIBRATION_DURATION_SETTINGS));
161             }
162         }
163 
164         final boolean showPopupOption = res.getBoolean(
165                 R.bool.config_enable_show_popup_on_keypress_option);
166         if (!showPopupOption) {
167             generalSettings.removePreference(findPreference(PREF_POPUP_ON));
168         }
169 
170         final boolean showBigramSuggestionsOption = res.getBoolean(
171                 R.bool.config_enable_next_word_suggestions_option);
172         if (!showBigramSuggestionsOption) {
173             textCorrectionGroup.removePreference(mBigramSuggestion);
174             if (null != mBigramPrediction) {
175                 textCorrectionGroup.removePreference(mBigramPrediction);
176             }
177         }
178 
179         final CheckBoxPreference includeOtherImesInLanguageSwitchList =
180                 (CheckBoxPreference)findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST);
181         includeOtherImesInLanguageSwitchList.setEnabled(
182                 !SettingsValues.isLanguageSwitchKeySupressed(prefs));
183 
184         mKeyPreviewPopupDismissDelay =
185                 (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
186         final String[] entries = new String[] {
187                 res.getString(R.string.key_preview_popup_dismiss_no_delay),
188                 res.getString(R.string.key_preview_popup_dismiss_default_delay),
189         };
190         final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
191                 R.integer.config_key_preview_linger_timeout));
192         mKeyPreviewPopupDismissDelay.setEntries(entries);
193         mKeyPreviewPopupDismissDelay.setEntryValues(
194                 new String[] { "0", popupDismissDelayDefaultValue });
195         if (null == mKeyPreviewPopupDismissDelay.getValue()) {
196             mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
197         }
198         mKeyPreviewPopupDismissDelay.setEnabled(
199                 SettingsValues.isKeyPreviewPopupEnabled(prefs, res));
200 
201         final PreferenceScreen dictionaryLink =
202                 (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY);
203         final Intent intent = dictionaryLink.getIntent();
204 
205         final int number = context.getPackageManager().queryIntentActivities(intent, 0).size();
206         if (0 >= number) {
207             textCorrectionGroup.removePreference(dictionaryLink);
208         }
209 
210         final boolean showUsabilityStudyModeOption =
211                 res.getBoolean(R.bool.config_enable_usability_study_mode_option)
212                         || ProductionFlag.IS_EXPERIMENTAL || ENABLE_EXPERIMENTAL_SETTINGS;
213         final Preference usabilityStudyPref = findPreference(PREF_USABILITY_STUDY_MODE);
214         if (!showUsabilityStudyModeOption) {
215             if (usabilityStudyPref != null) {
216                 miscSettings.removePreference(usabilityStudyPref);
217             }
218         }
219         if (ProductionFlag.IS_EXPERIMENTAL) {
220             if (usabilityStudyPref instanceof CheckBoxPreference) {
221                 CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
222                 checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE, true));
223                 checkbox.setSummary(R.string.settings_warning_researcher_mode);
224             }
225         }
226 
227         mKeypressVibrationDurationSettingsPref =
228                 (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS);
229         if (mKeypressVibrationDurationSettingsPref != null) {
230             mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener(
231                     new OnPreferenceClickListener() {
232                         @Override
233                         public boolean onPreferenceClick(Preference arg0) {
234                             showKeypressVibrationDurationSettingsDialog();
235                             return true;
236                         }
237                     });
238             updateKeypressVibrationDurationSettingsSummary(prefs, res);
239         }
240 
241         mKeypressSoundVolumeSettingsPref =
242                 (PreferenceScreen) findPreference(PREF_KEYPRESS_SOUND_VOLUME);
243         if (mKeypressSoundVolumeSettingsPref != null) {
244             mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener(
245                     new OnPreferenceClickListener() {
246                         @Override
247                         public boolean onPreferenceClick(Preference arg0) {
248                             showKeypressSoundVolumeSettingDialog();
249                             return true;
250                         }
251                     });
252             updateKeypressSoundVolumeSummary(prefs, res);
253         }
254         refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res);
255     }
256 
257     @Override
onResume()258     public void onResume() {
259         super.onResume();
260         final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
261         if (isShortcutImeEnabled) {
262             updateVoiceModeSummary();
263         } else {
264             getPreferenceScreen().removePreference(mVoicePreference);
265         }
266         updateShowCorrectionSuggestionsSummary();
267         updateKeyPreviewPopupDelaySummary();
268         updateCustomInputStylesSummary();
269     }
270 
271     @Override
onDestroy()272     public void onDestroy() {
273         getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
274                 this);
275         super.onDestroy();
276     }
277 
278     @Override
onSharedPreferenceChanged(SharedPreferences prefs, String key)279     public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
280         (new BackupManager(getActivity())).dataChanged();
281         if (key.equals(PREF_POPUP_ON)) {
282             final ListPreference popupDismissDelay =
283                 (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
284             if (null != popupDismissDelay) {
285                 popupDismissDelay.setEnabled(prefs.getBoolean(PREF_POPUP_ON, true));
286             }
287         } else if (key.equals(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) {
288             final CheckBoxPreference includeOtherImesInLanguageSwicthList =
289                     (CheckBoxPreference)findPreference(
290                             PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST);
291             includeOtherImesInLanguageSwicthList.setEnabled(
292                     !SettingsValues.isLanguageSwitchKeySupressed(prefs));
293         }
294         ensureConsistencyOfAutoCorrectionSettings();
295         updateVoiceModeSummary();
296         updateShowCorrectionSuggestionsSummary();
297         updateKeyPreviewPopupDelaySummary();
298         refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
299     }
300 
updateShowCorrectionSuggestionsSummary()301     private void updateShowCorrectionSuggestionsSummary() {
302         mShowCorrectionSuggestionsPreference.setSummary(
303                 getResources().getStringArray(R.array.prefs_suggestion_visibilities)
304                 [mShowCorrectionSuggestionsPreference.findIndexOfValue(
305                         mShowCorrectionSuggestionsPreference.getValue())]);
306     }
307 
updateCustomInputStylesSummary()308     private void updateCustomInputStylesSummary() {
309         final PreferenceScreen customInputStyles =
310                 (PreferenceScreen)findPreference(PREF_CUSTOM_INPUT_STYLES);
311         final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
312         final Resources res = getResources();
313         final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res);
314         final InputMethodSubtype[] subtypes =
315                 AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype);
316         final StringBuilder styles = new StringBuilder();
317         for (final InputMethodSubtype subtype : subtypes) {
318             if (styles.length() > 0) styles.append(", ");
319             styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res));
320         }
321         customInputStyles.setSummary(styles);
322     }
323 
updateKeyPreviewPopupDelaySummary()324     private void updateKeyPreviewPopupDelaySummary() {
325         final ListPreference lp = mKeyPreviewPopupDismissDelay;
326         lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]);
327     }
328 
updateVoiceModeSummary()329     private void updateVoiceModeSummary() {
330         mVoicePreference.setSummary(
331                 getResources().getStringArray(R.array.voice_input_modes_summary)
332                 [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]);
333     }
334 
refreshEnablingsOfKeypressSoundAndVibrationSettings( SharedPreferences sp, Resources res)335     private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
336             SharedPreferences sp, Resources res) {
337         if (mKeypressVibrationDurationSettingsPref != null) {
338             final boolean hasVibrator = VibratorUtils.getInstance(getActivity()).hasVibrator();
339             final boolean vibrateOn = hasVibrator && sp.getBoolean(Settings.PREF_VIBRATE_ON,
340                     res.getBoolean(R.bool.config_default_vibration_enabled));
341             mKeypressVibrationDurationSettingsPref.setEnabled(vibrateOn);
342         }
343 
344         if (mKeypressSoundVolumeSettingsPref != null) {
345             final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON,
346                     res.getBoolean(R.bool.config_default_sound_enabled));
347             mKeypressSoundVolumeSettingsPref.setEnabled(soundOn);
348         }
349     }
350 
updateKeypressVibrationDurationSettingsSummary( SharedPreferences sp, Resources res)351     private void updateKeypressVibrationDurationSettingsSummary(
352             SharedPreferences sp, Resources res) {
353         if (mKeypressVibrationDurationSettingsPref != null) {
354             mKeypressVibrationDurationSettingsPref.setSummary(
355                     SettingsValues.getCurrentVibrationDuration(sp, res)
356                             + res.getString(R.string.settings_ms));
357         }
358     }
359 
showKeypressVibrationDurationSettingsDialog()360     private void showKeypressVibrationDurationSettingsDialog() {
361         final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
362         final Context context = getActivity();
363         final Resources res = context.getResources();
364         final AlertDialog.Builder builder = new AlertDialog.Builder(context);
365         builder.setTitle(R.string.prefs_keypress_vibration_duration_settings);
366         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
367             @Override
368             public void onClick(DialogInterface dialog, int whichButton) {
369                 final int ms = Integer.valueOf(
370                         mKeypressVibrationDurationSettingsTextView.getText().toString());
371                 sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
372                 updateKeypressVibrationDurationSettingsSummary(sp, res);
373             }
374         });
375         builder.setNegativeButton(android.R.string.cancel,  new DialogInterface.OnClickListener() {
376             @Override
377             public void onClick(DialogInterface dialog, int whichButton) {
378                 dialog.dismiss();
379             }
380         });
381         final View v = LayoutInflater.from(context).inflate(
382                 R.layout.vibration_settings_dialog, null);
383         final int currentMs = SettingsValues.getCurrentVibrationDuration(
384                 getPreferenceManager().getSharedPreferences(), getResources());
385         mKeypressVibrationDurationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value);
386         final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings);
387         sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
388             @Override
389             public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
390                 final int tempMs = arg1;
391                 mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(tempMs));
392             }
393 
394             @Override
395             public void onStartTrackingTouch(SeekBar arg0) {
396             }
397 
398             @Override
399             public void onStopTrackingTouch(SeekBar arg0) {
400                 final int tempMs = arg0.getProgress();
401                 VibratorUtils.getInstance(context).vibrate(tempMs);
402             }
403         });
404         sb.setProgress(currentMs);
405         mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(currentMs));
406         builder.setView(v);
407         builder.create().show();
408     }
409 
updateKeypressSoundVolumeSummary(SharedPreferences sp, Resources res)410     private void updateKeypressSoundVolumeSummary(SharedPreferences sp, Resources res) {
411         if (mKeypressSoundVolumeSettingsPref != null) {
412             mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf(
413                     (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100)));
414         }
415     }
416 
showKeypressSoundVolumeSettingDialog()417     private void showKeypressSoundVolumeSettingDialog() {
418         final Context context = getActivity();
419         final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
420         final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
421         final Resources res = context.getResources();
422         final AlertDialog.Builder builder = new AlertDialog.Builder(context);
423         builder.setTitle(R.string.prefs_keypress_sound_volume_settings);
424         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
425             @Override
426             public void onClick(DialogInterface dialog, int whichButton) {
427                 final float volume =
428                         ((float)Integer.valueOf(
429                                 mKeypressSoundVolumeSettingsTextView.getText().toString())) / 100;
430                 sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply();
431                 updateKeypressSoundVolumeSummary(sp, res);
432             }
433         });
434         builder.setNegativeButton(android.R.string.cancel,  new DialogInterface.OnClickListener() {
435             @Override
436             public void onClick(DialogInterface dialog, int whichButton) {
437                 dialog.dismiss();
438             }
439         });
440         final View v = LayoutInflater.from(context).inflate(
441                 R.layout.sound_effect_volume_dialog, null);
442         final int currentVolumeInt =
443                 (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100);
444         mKeypressSoundVolumeSettingsTextView =
445                 (TextView)v.findViewById(R.id.sound_effect_volume_value);
446         final SeekBar sb = (SeekBar)v.findViewById(R.id.sound_effect_volume_bar);
447         sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
448             @Override
449             public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
450                 final int tempVolume = arg1;
451                 mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(tempVolume));
452             }
453 
454             @Override
455             public void onStartTrackingTouch(SeekBar arg0) {
456             }
457 
458             @Override
459             public void onStopTrackingTouch(SeekBar arg0) {
460                 final float tempVolume = ((float)arg0.getProgress()) / 100;
461                 am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, tempVolume);
462             }
463         });
464         sb.setProgress(currentVolumeInt);
465         mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(currentVolumeInt));
466         builder.setView(v);
467         builder.create().show();
468     }
469 }
470