• 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");
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