SettingsFragment.java revision 00b49cad9cc8a350bde8210d50c4b638908ef1c4
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
17package com.android.inputmethod.latin.settings;
18
19import android.app.Activity;
20import android.app.backup.BackupManager;
21import android.content.Context;
22import android.content.Intent;
23import android.content.SharedPreferences;
24import android.content.res.Resources;
25import android.media.AudioManager;
26import android.os.Bundle;
27import android.preference.ListPreference;
28import android.preference.Preference;
29import android.preference.PreferenceGroup;
30import android.preference.PreferenceScreen;
31import android.preference.TwoStatePreference;
32import android.util.Log;
33import android.view.Menu;
34import android.view.MenuInflater;
35import android.view.MenuItem;
36
37import com.android.inputmethod.keyboard.KeyboardTheme;
38import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
39import com.android.inputmethod.latin.R;
40import com.android.inputmethod.latin.define.ProductionFlags;
41import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
42import com.android.inputmethod.latin.utils.ApplicationUtils;
43import com.android.inputmethod.latin.utils.FeedbackUtils;
44import com.android.inputmethodcommon.InputMethodSettingsFragment;
45
46public final class SettingsFragment extends InputMethodSettingsFragment
47        implements SharedPreferences.OnSharedPreferenceChangeListener {
48    private static final String TAG = SettingsFragment.class.getSimpleName();
49
50    private static final int NO_MENU_GROUP = Menu.NONE; // We don't care about menu grouping.
51    private static final int MENU_FEEDBACK = Menu.FIRST; // The first menu item id and order.
52    private static final int MENU_ABOUT = Menu.FIRST + 1; // The second menu item id and order.
53
54    private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) {
55        final Preference preference = findPreference(preferenceKey);
56        if (preference != null) {
57            preference.setEnabled(enabled);
58        }
59    }
60
61    private void updateListPreferenceSummaryToCurrentValue(final String prefKey) {
62        // Because the "%s" summary trick of {@link ListPreference} doesn't work properly before
63        // KitKat, we need to update the summary programmatically.
64        final ListPreference listPreference = (ListPreference)findPreference(prefKey);
65        if (listPreference == null) {
66            return;
67        }
68        final CharSequence entries[] = listPreference.getEntries();
69        final int entryIndex = listPreference.findIndexOfValue(listPreference.getValue());
70        listPreference.setSummary(entryIndex < 0 ? null : entries[entryIndex]);
71    }
72
73    private static void removePreference(final String preferenceKey, final PreferenceGroup parent) {
74        if (parent == null) {
75            return;
76        }
77        final Preference preference = parent.findPreference(preferenceKey);
78        if (preference != null) {
79            parent.removePreference(preference);
80        }
81    }
82
83    @Override
84    public void onCreate(final Bundle icicle) {
85        super.onCreate(icicle);
86        setHasOptionsMenu(true);
87        setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
88        setSubtypeEnablerTitle(R.string.select_language);
89        addPreferencesFromResource(R.xml.prefs);
90        final PreferenceScreen preferenceScreen = getPreferenceScreen();
91        TwoStatePreferenceHelper.replaceCheckBoxPreferencesBySwitchPreferences(preferenceScreen);
92        preferenceScreen.setTitle(
93                ApplicationUtils.getActivityTitleResId(getActivity(), SettingsActivity.class));
94
95        final Resources res = getResources();
96        final Context context = getActivity();
97
98        // When we are called from the Settings application but we are not already running, some
99        // singleton and utility classes may not have been initialized.  We have to call
100        // initialization method of these classes here. See {@link LatinIME#onCreate()}.
101        AudioAndHapticFeedbackManager.init(context);
102
103        final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
104        prefs.registerOnSharedPreferenceChangeListener(this);
105
106        final PreferenceScreen advancedScreen =
107                (PreferenceScreen) findPreference(Settings.SCREEN_ADVANCED);
108        final PreferenceScreen debugScreen =
109                (PreferenceScreen) findPreference(Settings.SCREEN_DEBUG);
110
111        if (!Settings.isInternal(prefs)) {
112            advancedScreen.removePreference(debugScreen);
113        }
114
115        if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) {
116            removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedScreen);
117        }
118
119        // TODO: consolidate key preview dismiss delay with the key preview animation parameters.
120        if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) {
121            removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedScreen);
122        } else {
123            // TODO: Cleanup this setup.
124            final ListPreference keyPreviewPopupDismissDelay =
125                    (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
126            final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
127                    R.integer.config_key_preview_linger_timeout));
128            keyPreviewPopupDismissDelay.setEntries(new String[] {
129                    res.getString(R.string.key_preview_popup_dismiss_no_delay),
130                    res.getString(R.string.key_preview_popup_dismiss_default_delay),
131            });
132            keyPreviewPopupDismissDelay.setEntryValues(new String[] {
133                    "0",
134                    popupDismissDelayDefaultValue
135            });
136            if (null == keyPreviewPopupDismissDelay.getValue()) {
137                keyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
138            }
139            keyPreviewPopupDismissDelay.setEnabled(
140                    Settings.readKeyPreviewPopupEnabled(prefs, res));
141        }
142
143        if (!res.getBoolean(R.bool.config_setup_wizard_available)) {
144            removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedScreen);
145        }
146
147        if (ProductionFlags.IS_METRICS_LOGGING_SUPPORTED) {
148            final Preference enableMetricsLogging =
149                    findPreference(Settings.PREF_ENABLE_METRICS_LOGGING);
150            if (enableMetricsLogging != null) {
151                final int applicationLabelRes = context.getApplicationInfo().labelRes;
152                final String applicationName = res.getString(applicationLabelRes);
153                final String enableMetricsLoggingTitle = res.getString(
154                        R.string.enable_metrics_logging, applicationName);
155                enableMetricsLogging.setTitle(enableMetricsLoggingTitle);
156            }
157        } else {
158            removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, advancedScreen);
159        }
160
161        if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) {
162            getPreferenceScreen().removePreference(findPreference(Settings.SCREEN_GESTURE));
163        }
164
165        AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
166
167        setupKeypressVibrationDurationSettings(prefs, res);
168        setupKeypressSoundVolumeSettings(prefs, res);
169        refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res);
170    }
171
172    @Override
173    public void onResume() {
174        super.onResume();
175        final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
176        final TwoStatePreference showSetupWizardIcon =
177                (TwoStatePreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON);
178        if (showSetupWizardIcon != null) {
179            showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity()));
180        }
181        updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
182        final ListPreference keyboardThemePref = (ListPreference)findPreference(
183                Settings.PREF_KEYBOARD_THEME);
184        if (keyboardThemePref != null) {
185            final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
186            final String value = Integer.toString(keyboardTheme.mThemeId);
187            final CharSequence entries[] = keyboardThemePref.getEntries();
188            final int entryIndex = keyboardThemePref.findIndexOfValue(value);
189            keyboardThemePref.setSummary(entryIndex < 0 ? null : entries[entryIndex]);
190            keyboardThemePref.setValue(value);
191        }
192    }
193
194    @Override
195    public void onPause() {
196        super.onPause();
197        final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
198        final ListPreference keyboardThemePref = (ListPreference)findPreference(
199                Settings.PREF_KEYBOARD_THEME);
200        if (keyboardThemePref != null) {
201            KeyboardTheme.saveKeyboardThemeId(keyboardThemePref.getValue(), prefs);
202        }
203    }
204
205    @Override
206    public void onDestroy() {
207        getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
208                this);
209        super.onDestroy();
210    }
211
212    @Override
213    public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
214        final Activity activity = getActivity();
215        if (activity == null) {
216            // TODO: Introduce a static function to register this class and ensure that
217            // onCreate must be called before "onSharedPreferenceChanged" is called.
218            Log.w(TAG, "onSharedPreferenceChanged called before activity starts.");
219            return;
220        }
221        (new BackupManager(activity)).dataChanged();
222        final Resources res = getResources();
223        if (key.equals(Settings.PREF_POPUP_ON)) {
224            setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
225                    Settings.readKeyPreviewPopupEnabled(prefs, res));
226        } else if (key.equals(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
227            LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity());
228        }
229        updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
230        updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_THEME);
231        refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
232    }
233
234    private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
235            final SharedPreferences sp, final Resources res) {
236        setPreferenceEnabled(Settings.PREF_VIBRATION_DURATION_SETTINGS,
237                Settings.readVibrationEnabled(sp, res));
238        setPreferenceEnabled(Settings.PREF_KEYPRESS_SOUND_VOLUME,
239                Settings.readKeypressSoundEnabled(sp, res));
240    }
241
242    private void setupKeypressVibrationDurationSettings(final SharedPreferences sp,
243            final Resources res) {
244        final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
245                Settings.PREF_VIBRATION_DURATION_SETTINGS);
246        if (pref == null) {
247            return;
248        }
249        pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
250            @Override
251            public void writeValue(final int value, final String key) {
252                sp.edit().putInt(key, value).apply();
253            }
254
255            @Override
256            public void writeDefaultValue(final String key) {
257                sp.edit().remove(key).apply();
258            }
259
260            @Override
261            public int readValue(final String key) {
262                return Settings.readKeypressVibrationDuration(sp, res);
263            }
264
265            @Override
266            public int readDefaultValue(final String key) {
267                return Settings.readDefaultKeypressVibrationDuration(res);
268            }
269
270            @Override
271            public void feedbackValue(final int value) {
272                AudioAndHapticFeedbackManager.getInstance().vibrate(value);
273            }
274
275            @Override
276            public String getValueText(final int value) {
277                if (value < 0) {
278                    return res.getString(R.string.settings_system_default);
279                }
280                return res.getString(R.string.abbreviation_unit_milliseconds, value);
281            }
282        });
283    }
284
285    private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) {
286        final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
287                Settings.PREF_KEYPRESS_SOUND_VOLUME);
288        if (pref == null) {
289            return;
290        }
291        final AudioManager am = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
292        pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
293            private static final float PERCENTAGE_FLOAT = 100.0f;
294
295            private float getValueFromPercentage(final int percentage) {
296                return percentage / PERCENTAGE_FLOAT;
297            }
298
299            private int getPercentageFromValue(final float floatValue) {
300                return (int)(floatValue * PERCENTAGE_FLOAT);
301            }
302
303            @Override
304            public void writeValue(final int value, final String key) {
305                sp.edit().putFloat(key, getValueFromPercentage(value)).apply();
306            }
307
308            @Override
309            public void writeDefaultValue(final String key) {
310                sp.edit().remove(key).apply();
311            }
312
313            @Override
314            public int readValue(final String key) {
315                return getPercentageFromValue(Settings.readKeypressSoundVolume(sp, res));
316            }
317
318            @Override
319            public int readDefaultValue(final String key) {
320                return getPercentageFromValue(Settings.readDefaultKeypressSoundVolume(res));
321            }
322
323            @Override
324            public String getValueText(final int value) {
325                if (value < 0) {
326                    return res.getString(R.string.settings_system_default);
327                }
328                return Integer.toString(value);
329            }
330
331            @Override
332            public void feedbackValue(final int value) {
333                am.playSoundEffect(
334                        AudioManager.FX_KEYPRESS_STANDARD, getValueFromPercentage(value));
335            }
336        });
337    }
338
339    @Override
340    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
341        if (FeedbackUtils.isFeedbackFormSupported()) {
342            menu.add(NO_MENU_GROUP, MENU_FEEDBACK /* itemId */, MENU_FEEDBACK /* order */,
343                    R.string.send_feedback);
344        }
345        final int aboutResId = FeedbackUtils.getAboutKeyboardTitleResId();
346        if (aboutResId != 0) {
347            menu.add(NO_MENU_GROUP, MENU_ABOUT /* itemId */, MENU_ABOUT /* order */, aboutResId);
348        }
349    }
350
351    @Override
352    public boolean onOptionsItemSelected(final MenuItem item) {
353        final int itemId = item.getItemId();
354        if (itemId == MENU_FEEDBACK) {
355            FeedbackUtils.showFeedbackForm(getActivity());
356            return true;
357        }
358        if (itemId == MENU_ABOUT) {
359            final Intent aboutIntent = FeedbackUtils.getAboutKeyboardIntent(getActivity());
360            if (aboutIntent != null) {
361                startActivity(aboutIntent);
362                return true;
363            }
364        }
365        return super.onOptionsItemSelected(item);
366    }
367}
368