Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2013 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.settings;
     18 
     19 import android.content.Context;
     20 import android.content.SharedPreferences;
     21 import android.content.pm.ApplicationInfo;
     22 import android.content.res.Resources;
     23 import android.preference.PreferenceManager;
     24 import android.util.Log;
     25 
     26 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
     27 import com.android.inputmethod.latin.InputAttributes;
     28 import com.android.inputmethod.latin.R;
     29 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
     30 import com.android.inputmethod.latin.utils.LocaleUtils;
     31 import com.android.inputmethod.latin.utils.ResourceUtils;
     32 import com.android.inputmethod.latin.utils.RunInLocale;
     33 import com.android.inputmethod.latin.utils.StringUtils;
     34 
     35 import java.util.HashMap;
     36 import java.util.Locale;
     37 import java.util.concurrent.locks.ReentrantLock;
     38 
     39 public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener {
     40     private static final String TAG = Settings.class.getSimpleName();
     41     // In the same order as xml/prefs.xml
     42     public static final String PREF_GENERAL_SETTINGS = "general_settings";
     43     public static final String PREF_AUTO_CAP = "auto_cap";
     44     public static final String PREF_VIBRATE_ON = "vibrate_on";
     45     public static final String PREF_SOUND_ON = "sound_on";
     46     public static final String PREF_POPUP_ON = "popup_on";
     47     // PREF_VOICE_MODE_OBSOLETE is obsolete. Use PREF_VOICE_INPUT_KEY instead.
     48     public static final String PREF_VOICE_MODE_OBSOLETE = "voice_mode";
     49     public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key";
     50     public static final String PREF_CORRECTION_SETTINGS = "correction_settings";
     51     public static final String PREF_EDIT_PERSONAL_DICTIONARY = "edit_personal_dictionary";
     52     public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key";
     53     public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
     54     public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting";
     55     public static final String PREF_MISC_SETTINGS = "misc_settings";
     56     public static final String PREF_LAST_USER_DICTIONARY_WRITE_TIME =
     57             "last_user_dictionary_write_time";
     58     public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings";
     59     public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict";
     60     public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD =
     61             "pref_key_use_double_space_period";
     62     public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE =
     63             "pref_key_block_potentially_offensive";
     64     public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY =
     65             "pref_show_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_BIGRAM_PREDICTIONS = "next_word_prediction";
     72     public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings";
     73     public static final String PREF_GESTURE_INPUT = "gesture_input";
     74     public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview";
     75     public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
     76     public static final String PREF_VIBRATION_DURATION_SETTINGS =
     77             "pref_vibration_duration_settings";
     78     public static final String PREF_KEYPRESS_SOUND_VOLUME =
     79             "pref_keypress_sound_volume";
     80     public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail";
     81     public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT =
     82             "pref_gesture_floating_preview_text";
     83     public static final String PREF_SHOW_SETUP_WIZARD_ICON = "pref_show_setup_wizard_icon";
     84     public static final String PREF_PHRASE_GESTURE_ENABLED = "pref_gesture_space_aware";
     85 
     86     public static final String PREF_INPUT_LANGUAGE = "input_language";
     87     public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
     88     public static final String PREF_DEBUG_SETTINGS = "debug_settings";
     89     public static final String PREF_KEY_IS_INTERNAL = "pref_key_is_internal";
     90 
     91     // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead.
     92     // This is being used only for the backward compatibility.
     93     private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY =
     94             "pref_suppress_language_switch_key";
     95 
     96     private static final String PREF_LAST_USED_PERSONALIZATION_TOKEN =
     97             "pref_last_used_personalization_token";
     98     public static final String PREF_SEND_FEEDBACK = "send_feedback";
     99     public static final String PREF_ABOUT_KEYBOARD = "about_keyboard";
    100 
    101     // Emoji
    102     public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
    103     public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";
    104     public static final String PREF_LAST_SHOWN_EMOJI_CATEGORY_ID = "last_shown_emoji_category_id";
    105 
    106     private Resources mRes;
    107     private SharedPreferences mPrefs;
    108     private SettingsValues mSettingsValues;
    109     private final ReentrantLock mSettingsValuesLock = new ReentrantLock();
    110 
    111     private static final Settings sInstance = new Settings();
    112 
    113     public static Settings getInstance() {
    114         return sInstance;
    115     }
    116 
    117     public static void init(final Context context) {
    118         sInstance.onCreate(context);
    119     }
    120 
    121     private Settings() {
    122         // Intentional empty constructor for singleton.
    123     }
    124 
    125     private void onCreate(final Context context) {
    126         mRes = context.getResources();
    127         mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    128         mPrefs.registerOnSharedPreferenceChangeListener(this);
    129     }
    130 
    131     public void onDestroy() {
    132         mPrefs.unregisterOnSharedPreferenceChangeListener(this);
    133     }
    134 
    135     @Override
    136     public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
    137         mSettingsValuesLock.lock();
    138         try {
    139             if (mSettingsValues == null) {
    140                 // TODO: Introduce a static function to register this class and ensure that
    141                 // loadSettings must be called before "onSharedPreferenceChanged" is called.
    142                 Log.w(TAG, "onSharedPreferenceChanged called before loadSettings.");
    143                 return;
    144             }
    145             loadSettings(mSettingsValues.mLocale, mSettingsValues.mInputAttributes);
    146         } finally {
    147             mSettingsValuesLock.unlock();
    148         }
    149     }
    150 
    151     public void loadSettings(final Locale locale, final InputAttributes inputAttributes) {
    152         mSettingsValuesLock.lock();
    153         try {
    154             final SharedPreferences prefs = mPrefs;
    155             final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
    156                 @Override
    157                 protected SettingsValues job(final Resources res) {
    158                     return new SettingsValues(prefs, locale, res, inputAttributes);
    159                 }
    160             };
    161             mSettingsValues = job.runInLocale(mRes, locale);
    162         } finally {
    163             mSettingsValuesLock.unlock();
    164         }
    165     }
    166 
    167     // TODO: Remove this method and add proxy method to SettingsValues.
    168     public SettingsValues getCurrent() {
    169         return mSettingsValues;
    170     }
    171 
    172     public boolean isInternal() {
    173         return mSettingsValues.mIsInternal;
    174     }
    175 
    176     public String getWordSeparators() {
    177         return mSettingsValues.mWordSeparators;
    178     }
    179 
    180     public boolean isWordSeparator(final int code) {
    181         return mSettingsValues.isWordSeparator(code);
    182     }
    183 
    184     public boolean getBlockPotentiallyOffensive() {
    185         return mSettingsValues.mBlockPotentiallyOffensive;
    186     }
    187 
    188     // Accessed from the settings interface, hence public
    189     public static boolean readKeypressSoundEnabled(final SharedPreferences prefs,
    190             final Resources res) {
    191         return prefs.getBoolean(Settings.PREF_SOUND_ON,
    192                 res.getBoolean(R.bool.config_default_sound_enabled));
    193     }
    194 
    195     public static boolean readVibrationEnabled(final SharedPreferences prefs,
    196             final Resources res) {
    197         final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator();
    198         return hasVibrator && prefs.getBoolean(PREF_VIBRATE_ON,
    199                 res.getBoolean(R.bool.config_default_vibration_enabled));
    200     }
    201 
    202     public static boolean readAutoCorrectEnabled(final String currentAutoCorrectionSetting,
    203             final Resources res) {
    204         final String autoCorrectionOff = res.getString(
    205                 R.string.auto_correction_threshold_mode_index_off);
    206         return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
    207     }
    208 
    209     public static boolean readBlockPotentiallyOffensive(final SharedPreferences prefs,
    210             final Resources res) {
    211         return prefs.getBoolean(Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE,
    212                 res.getBoolean(R.bool.config_block_potentially_offensive));
    213     }
    214 
    215     public static boolean readFromBuildConfigIfGestureInputEnabled(final Resources res) {
    216         return res.getBoolean(R.bool.config_gesture_input_enabled_by_build_config);
    217     }
    218 
    219     public static boolean readGestureInputEnabled(final SharedPreferences prefs,
    220             final Resources res) {
    221         return readFromBuildConfigIfGestureInputEnabled(res)
    222                 && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true);
    223     }
    224 
    225     public static boolean readPhraseGestureEnabled(final SharedPreferences prefs,
    226             final Resources res) {
    227         return prefs.getBoolean(Settings.PREF_PHRASE_GESTURE_ENABLED,
    228                 res.getBoolean(R.bool.config_default_phrase_gesture_enabled));
    229     }
    230 
    231     public static boolean readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption(
    232             final Resources res) {
    233         return res.getBoolean(R.bool.config_enable_show_option_of_key_preview_popup);
    234     }
    235 
    236     public static boolean readKeyPreviewPopupEnabled(final SharedPreferences prefs,
    237             final Resources res) {
    238         final boolean defaultKeyPreviewPopup = res.getBoolean(
    239                 R.bool.config_default_key_preview_popup);
    240         if (!readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption(res)) {
    241             return defaultKeyPreviewPopup;
    242         }
    243         return prefs.getBoolean(PREF_POPUP_ON, defaultKeyPreviewPopup);
    244     }
    245 
    246     public static int readKeyPreviewPopupDismissDelay(final SharedPreferences prefs,
    247             final Resources res) {
    248         return Integer.parseInt(prefs.getString(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
    249                 Integer.toString(res.getInteger(
    250                         R.integer.config_key_preview_linger_timeout))));
    251     }
    252 
    253     public static boolean readShowsLanguageSwitchKey(final SharedPreferences prefs) {
    254         if (prefs.contains(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) {
    255             final boolean suppressLanguageSwitchKey = prefs.getBoolean(
    256                     PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false);
    257             final SharedPreferences.Editor editor = prefs.edit();
    258             editor.remove(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY);
    259             editor.putBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, !suppressLanguageSwitchKey);
    260             editor.apply();
    261         }
    262         return prefs.getBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, true);
    263     }
    264 
    265     public static String readPrefAdditionalSubtypes(final SharedPreferences prefs,
    266             final Resources res) {
    267         final String predefinedPrefSubtypes = AdditionalSubtypeUtils.createPrefSubtypes(
    268                 res.getStringArray(R.array.predefined_subtypes));
    269         return prefs.getString(PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes);
    270     }
    271 
    272     public static void writePrefAdditionalSubtypes(final SharedPreferences prefs,
    273             final String prefSubtypes) {
    274         prefs.edit().putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply();
    275     }
    276 
    277     public static float readKeypressSoundVolume(final SharedPreferences prefs,
    278             final Resources res) {
    279         final float volume = prefs.getFloat(PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
    280         return (volume >= 0) ? volume : readDefaultKeypressSoundVolume(res);
    281     }
    282 
    283     public static float readDefaultKeypressSoundVolume(final Resources res) {
    284         return Float.parseFloat(
    285                 ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes));
    286     }
    287 
    288     public static int readKeyLongpressTimeout(final SharedPreferences prefs,
    289             final Resources res) {
    290         final int ms = prefs.getInt(PREF_KEY_LONGPRESS_TIMEOUT, -1);
    291         return (ms >= 0) ? ms : readDefaultKeyLongpressTimeout(res);
    292     }
    293 
    294     public static int readDefaultKeyLongpressTimeout(final Resources res) {
    295         return res.getInteger(R.integer.config_default_longpress_key_timeout);
    296     }
    297 
    298     public static int readKeypressVibrationDuration(final SharedPreferences prefs,
    299             final Resources res) {
    300         final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1);
    301         return (ms >= 0) ? ms : readDefaultKeypressVibrationDuration(res);
    302     }
    303 
    304     public static int readDefaultKeypressVibrationDuration(final Resources res) {
    305         return Integer.parseInt(
    306                 ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations));
    307     }
    308 
    309     public static boolean readUsabilityStudyMode(final SharedPreferences prefs) {
    310         return prefs.getBoolean(DebugSettings.PREF_USABILITY_STUDY_MODE, true);
    311     }
    312 
    313     public static long readLastUserHistoryWriteTime(final SharedPreferences prefs,
    314             final String locale) {
    315         final String str = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, "");
    316         final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str);
    317         if (map.containsKey(locale)) {
    318             return map.get(locale);
    319         }
    320         return 0;
    321     }
    322 
    323     public static void writeLastUserHistoryWriteTime(final SharedPreferences prefs,
    324             final String locale) {
    325         final String oldStr = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, "");
    326         final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr);
    327         map.put(locale, System.currentTimeMillis());
    328         final String newStr = LocaleUtils.localeAndTimeHashMapToStr(map);
    329         prefs.edit().putString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply();
    330     }
    331 
    332     public static boolean readUseFullscreenMode(final Resources res) {
    333         return res.getBoolean(R.bool.config_use_fullscreen_mode);
    334     }
    335 
    336     public static boolean readShowSetupWizardIcon(final SharedPreferences prefs,
    337             final Context context) {
    338         final boolean enableSetupWizardByConfig = context.getResources().getBoolean(
    339                 R.bool.config_setup_wizard_available);
    340         if (!enableSetupWizardByConfig) {
    341             return false;
    342         }
    343         if (!prefs.contains(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
    344             final ApplicationInfo appInfo = context.getApplicationInfo();
    345             final boolean isApplicationInSystemImage =
    346                     (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    347             // Default value
    348             return !isApplicationInSystemImage;
    349         }
    350         return prefs.getBoolean(Settings.PREF_SHOW_SETUP_WIZARD_ICON, false);
    351     }
    352 
    353     public static boolean isInternal(final SharedPreferences prefs) {
    354         return prefs.getBoolean(Settings.PREF_KEY_IS_INTERNAL, false);
    355     }
    356 
    357     public static boolean readUseOnlyPersonalizationDictionaryForDebug(
    358             final SharedPreferences prefs) {
    359         return prefs.getBoolean(
    360                 DebugSettings.PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false);
    361     }
    362 
    363     public static boolean readBoostPersonalizationDictionaryForDebug(
    364             final SharedPreferences prefs) {
    365         return prefs.getBoolean(
    366                 DebugSettings.PREF_BOOST_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false);
    367     }
    368 
    369     public void writeLastUsedPersonalizationToken(byte[] token) {
    370         final String tokenStr = StringUtils.byteArrayToHexString(token);
    371         mPrefs.edit().putString(PREF_LAST_USED_PERSONALIZATION_TOKEN, tokenStr).apply();
    372     }
    373 
    374     public byte[] readLastUsedPersonalizationToken() {
    375         final String tokenStr = mPrefs.getString(PREF_LAST_USED_PERSONALIZATION_TOKEN, null);
    376         return StringUtils.hexStringToByteArray(tokenStr);
    377     }
    378 
    379     public static void writeEmojiRecentKeys(final SharedPreferences prefs, String str) {
    380         prefs.edit().putString(PREF_EMOJI_RECENT_KEYS, str).apply();
    381     }
    382 
    383     public static String readEmojiRecentKeys(final SharedPreferences prefs) {
    384         return prefs.getString(PREF_EMOJI_RECENT_KEYS, "");
    385     }
    386 
    387     public static void writeLastTypedEmojiCategoryPageId(
    388             final SharedPreferences prefs, final int categoryId, final int categoryPageId) {
    389         final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + categoryId;
    390         prefs.edit().putInt(key, categoryPageId).apply();
    391     }
    392 
    393     public static int readLastTypedEmojiCategoryPageId(
    394             final SharedPreferences prefs, final int categoryId) {
    395         final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + categoryId;
    396         return prefs.getInt(key, 0);
    397     }
    398 
    399     public static void writeLastShownEmojiCategoryId(
    400             final SharedPreferences prefs, final int categoryId) {
    401         prefs.edit().putInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_ID, categoryId).apply();
    402     }
    403 
    404     public static int readLastShownEmojiCategoryId(
    405             final SharedPreferences prefs, final int defValue) {
    406         return prefs.getInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_ID, defValue);
    407     }
    408 }
    409