SettingsValues.java revision c239a34262358e51aedb15f2e315bbe9bcd57c4b
1/* 2 * Copyright (C) 2011 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.content.SharedPreferences; 20import android.content.res.Configuration; 21import android.content.res.Resources; 22import android.util.Log; 23import android.view.inputmethod.EditorInfo; 24 25import com.android.inputmethod.annotations.UsedForTesting; 26import com.android.inputmethod.keyboard.internal.KeySpecParser; 27import com.android.inputmethod.latin.Dictionary; 28import com.android.inputmethod.latin.InputAttributes; 29import com.android.inputmethod.latin.R; 30import com.android.inputmethod.latin.RichInputMethodManager; 31import com.android.inputmethod.latin.SubtypeSwitcher; 32import com.android.inputmethod.latin.SuggestedWords; 33import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 34import com.android.inputmethod.latin.utils.CollectionUtils; 35import com.android.inputmethod.latin.utils.InputTypeUtils; 36import com.android.inputmethod.latin.utils.StringUtils; 37 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.Locale; 41 42/** 43 * When you call the constructor of this class, you may want to change the current system locale by 44 * using {@link com.android.inputmethod.latin.utils.RunInLocale}. 45 */ 46public final class SettingsValues { 47 private static final String TAG = SettingsValues.class.getSimpleName(); 48 // "floatNegativeInfinity" is a special marker string for Float.NEGATIVE_INFINITE 49 // currently used for auto-correction 50 private static final String FLOAT_NEGATIVE_INFINITY_MARKER_STRING = "floatNegativeInfinity"; 51 52 // From resources: 53 public final int mDelayUpdateOldSuggestions; 54 public final int[] mSymbolsPrecededBySpace; 55 public final int[] mSymbolsFollowedBySpace; 56 public final int[] mWordConnectors; 57 public final SuggestedWords mSuggestPuncList; 58 public final String mWordSeparators; 59 public final CharSequence mHintToSaveText; 60 public final boolean mCurrentLanguageHasSpaces; 61 62 // From preferences, in the same order as xml/prefs.xml: 63 public final boolean mAutoCap; 64 public final boolean mVibrateOn; 65 public final boolean mSoundOn; 66 public final boolean mKeyPreviewPopupOn; 67 private final String mVoiceMode; 68 public final boolean mIncludesOtherImesInLanguageSwitchList; 69 public final boolean mShowsLanguageSwitchKey; 70 public final boolean mUseContactsDict; 71 public final boolean mUseDoubleSpacePeriod; 72 public final boolean mBlockPotentiallyOffensive; 73 // Use bigrams to predict the next word when there is no input for it yet 74 public final boolean mBigramPredictionEnabled; 75 public final boolean mGestureInputEnabled; 76 public final boolean mGestureTrailEnabled; 77 public final boolean mGestureFloatingPreviewTextEnabled; 78 public final boolean mSlidingKeyInputPreviewEnabled; 79 public final int mKeyLongpressTimeout; 80 public final Locale mLocale; 81 82 // From the input box 83 public final InputAttributes mInputAttributes; 84 85 // Deduced settings 86 public final int mKeypressVibrationDuration; 87 public final float mKeypressSoundVolume; 88 public final int mKeyPreviewPopupDismissDelay; 89 private final boolean mAutoCorrectEnabled; 90 public final float mAutoCorrectionThreshold; 91 public final boolean mCorrectionEnabled; 92 public final int mSuggestionVisibility; 93 private final boolean mVoiceKeyEnabled; 94 private final boolean mVoiceKeyOnMain; 95 96 // Setting values for additional features 97 public final int[] mAdditionalFeaturesSettingValues = 98 new int[AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE]; 99 100 // Debug settings 101 public final boolean mIsInternal; 102 103 public SettingsValues(final SharedPreferences prefs, final Locale locale, final Resources res, 104 final InputAttributes inputAttributes) { 105 mLocale = locale; 106 // Get the resources 107 mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); 108 mSymbolsPrecededBySpace = 109 StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space)); 110 Arrays.sort(mSymbolsPrecededBySpace); 111 mSymbolsFollowedBySpace = 112 StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space)); 113 Arrays.sort(mSymbolsFollowedBySpace); 114 mWordConnectors = 115 StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors)); 116 Arrays.sort(mWordConnectors); 117 final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString( 118 R.string.suggested_punctuations)); 119 mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); 120 mWordSeparators = res.getString(R.string.symbols_word_separators); 121 mHintToSaveText = res.getText(R.string.hint_add_to_dictionary); 122 mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces); 123 124 // Store the input attributes 125 if (null == inputAttributes) { 126 mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */); 127 } else { 128 mInputAttributes = inputAttributes; 129 } 130 131 // Get the settings preferences 132 mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); 133 mVibrateOn = Settings.readVibrationEnabled(prefs, res); 134 mSoundOn = Settings.readKeypressSoundEnabled(prefs, res); 135 mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res); 136 mSlidingKeyInputPreviewEnabled = prefs.getBoolean( 137 Settings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); 138 final String voiceModeMain = res.getString(R.string.voice_mode_main); 139 final String voiceModeOff = res.getString(R.string.voice_mode_off); 140 mVoiceMode = prefs.getString(Settings.PREF_VOICE_MODE, voiceModeMain); 141 final String autoCorrectionThresholdRawValue = prefs.getString( 142 Settings.PREF_AUTO_CORRECTION_THRESHOLD, 143 res.getString(R.string.auto_correction_threshold_mode_index_modest)); 144 mIncludesOtherImesInLanguageSwitchList = prefs.getBoolean( 145 Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); 146 mShowsLanguageSwitchKey = Settings.readShowsLanguageSwitchKey(prefs); 147 mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); 148 mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); 149 mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res); 150 mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res); 151 mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); 152 153 // Compute other readable settings 154 mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res); 155 mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res); 156 mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); 157 mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); 158 mAutoCorrectionThreshold = readAutoCorrectionThreshold(res, 159 autoCorrectionThresholdRawValue); 160 mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff); 161 mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain); 162 mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res); 163 mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); 164 mGestureFloatingPreviewTextEnabled = prefs.getBoolean( 165 Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); 166 mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; 167 final String showSuggestionsSetting = prefs.getString( 168 Settings.PREF_SHOW_SUGGESTIONS_SETTING, 169 res.getString(R.string.prefs_suggestion_visibility_default_value)); 170 mSuggestionVisibility = createSuggestionVisibility(res, showSuggestionsSetting); 171 AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray( 172 prefs, mAdditionalFeaturesSettingValues); 173 mIsInternal = Settings.isInternal(prefs); 174 } 175 176 // Only for tests 177 private SettingsValues(final Locale locale) { 178 // TODO: locale is saved, but not used yet. May have to change this if tests require. 179 mLocale = locale; 180 mDelayUpdateOldSuggestions = 0; 181 mSymbolsPrecededBySpace = new int[] { '(', '[', '{', '&' }; 182 Arrays.sort(mSymbolsPrecededBySpace); 183 mSymbolsFollowedBySpace = new int[] { '.', ',', ';', ':', '!', '?', ')', ']', '}', '&' }; 184 Arrays.sort(mSymbolsFollowedBySpace); 185 mWordConnectors = new int[] { '\'', '-' }; 186 Arrays.sort(mWordConnectors); 187 final String[] suggestPuncsSpec = new String[] { "!", "?", ",", ":", ";" }; 188 mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); 189 mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\""; 190 mHintToSaveText = "Touch again to save"; 191 mCurrentLanguageHasSpaces = true; 192 mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */); 193 mAutoCap = true; 194 mVibrateOn = true; 195 mSoundOn = true; 196 mKeyPreviewPopupOn = true; 197 mSlidingKeyInputPreviewEnabled = true; 198 mVoiceMode = "0"; 199 mIncludesOtherImesInLanguageSwitchList = false; 200 mShowsLanguageSwitchKey = true; 201 mUseContactsDict = true; 202 mUseDoubleSpacePeriod = true; 203 mBlockPotentiallyOffensive = true; 204 mAutoCorrectEnabled = true; 205 mBigramPredictionEnabled = true; 206 mKeyLongpressTimeout = 300; 207 mKeypressVibrationDuration = 5; 208 mKeypressSoundVolume = 1; 209 mKeyPreviewPopupDismissDelay = 70; 210 mAutoCorrectionThreshold = 1; 211 mVoiceKeyEnabled = true; 212 mVoiceKeyOnMain = true; 213 mGestureInputEnabled = true; 214 mGestureTrailEnabled = true; 215 mGestureFloatingPreviewTextEnabled = true; 216 mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; 217 mSuggestionVisibility = 0; 218 mIsInternal = false; 219 } 220 221 @UsedForTesting 222 public static SettingsValues makeDummySettingsValuesForTest(final Locale locale) { 223 return new SettingsValues(locale); 224 } 225 226 public boolean isApplicationSpecifiedCompletionsOn() { 227 return mInputAttributes.mApplicationSpecifiedCompletionOn; 228 } 229 230 public boolean isSuggestionsRequested(final int displayOrientation) { 231 return mInputAttributes.mIsSettingsSuggestionStripOn 232 && (mCorrectionEnabled 233 || isSuggestionStripVisibleInOrientation(displayOrientation)); 234 } 235 236 public boolean isSuggestionStripVisibleInOrientation(final int orientation) { 237 return (mSuggestionVisibility == SUGGESTION_VISIBILITY_SHOW_VALUE) 238 || (mSuggestionVisibility == SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE 239 && orientation == Configuration.ORIENTATION_PORTRAIT); 240 } 241 242 public boolean isWordSeparator(final int code) { 243 return mWordSeparators.contains(String.valueOf((char)code)); 244 } 245 246 public boolean isWordConnector(final int code) { 247 return Arrays.binarySearch(mWordConnectors, code) >= 0; 248 } 249 250 public boolean isWordCodePoint(final int code) { 251 return Character.isLetter(code) || isWordConnector(code); 252 } 253 254 public boolean isUsuallyPrecededBySpace(final int code) { 255 return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0; 256 } 257 258 public boolean isUsuallyFollowedBySpace(final int code) { 259 return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0; 260 } 261 262 public boolean shouldInsertSpacesAutomatically() { 263 return mInputAttributes.mShouldInsertSpacesAutomatically; 264 } 265 266 public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) { 267 final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); 268 final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; 269 return shortcutImeEnabled && mVoiceKeyEnabled 270 && !InputTypeUtils.isPasswordInputType(inputType); 271 } 272 273 public boolean isVoiceKeyOnMain() { 274 return mVoiceKeyOnMain; 275 } 276 277 public boolean isLanguageSwitchKeyEnabled() { 278 if (!mShowsLanguageSwitchKey) { 279 return false; 280 } 281 final RichInputMethodManager imm = RichInputMethodManager.getInstance(); 282 if (mIncludesOtherImesInLanguageSwitchList) { 283 return imm.hasMultipleEnabledIMEsOrSubtypes(false /* include aux subtypes */); 284 } else { 285 return imm.hasMultipleEnabledSubtypesInThisIme(false /* include aux subtypes */); 286 } 287 } 288 289 public boolean isSameInputType(final EditorInfo editorInfo) { 290 return mInputAttributes.isSameInputType(editorInfo); 291 } 292 293 // Helper functions to create member values. 294 private static SuggestedWords createSuggestPuncList(final String[] puncs) { 295 final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList(); 296 if (puncs != null) { 297 for (final String puncSpec : puncs) { 298 // TODO: Stop using KeySpceParser.getLabel(). 299 puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), 300 SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, 301 Dictionary.TYPE_HARDCODED)); 302 } 303 } 304 return new SuggestedWords(puncList, 305 false /* typedWordValid */, 306 false /* hasAutoCorrectionCandidate */, 307 true /* isPunctuationSuggestions */, 308 false /* isObsoleteSuggestions */, 309 false /* isPrediction */); 310 } 311 312 private static final int SUGGESTION_VISIBILITY_SHOW_VALUE = 313 R.string.prefs_suggestion_visibility_show_value; 314 private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE = 315 R.string.prefs_suggestion_visibility_show_only_portrait_value; 316 private static final int SUGGESTION_VISIBILITY_HIDE_VALUE = 317 R.string.prefs_suggestion_visibility_hide_value; 318 private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { 319 SUGGESTION_VISIBILITY_SHOW_VALUE, 320 SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE, 321 SUGGESTION_VISIBILITY_HIDE_VALUE 322 }; 323 324 private static int createSuggestionVisibility(final Resources res, 325 final String suggestionVisiblityStr) { 326 for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { 327 if (suggestionVisiblityStr.equals(res.getString(visibility))) { 328 return visibility; 329 } 330 } 331 throw new RuntimeException("Bug: visibility string is not configured correctly"); 332 } 333 334 private static boolean readBigramPredictionEnabled(final SharedPreferences prefs, 335 final Resources res) { 336 return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( 337 R.bool.config_default_next_word_prediction)); 338 } 339 340 private static float readAutoCorrectionThreshold(final Resources res, 341 final String currentAutoCorrectionSetting) { 342 final String[] autoCorrectionThresholdValues = res.getStringArray( 343 R.array.auto_correction_threshold_values); 344 // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. 345 float autoCorrectionThreshold = Float.MAX_VALUE; 346 try { 347 final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); 348 if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { 349 final String val = autoCorrectionThresholdValues[arrayIndex]; 350 if (FLOAT_NEGATIVE_INFINITY_MARKER_STRING.equals(val)) { 351 autoCorrectionThreshold = Float.NEGATIVE_INFINITY; 352 } else { 353 autoCorrectionThreshold = Float.parseFloat(val); 354 } 355 } 356 } catch (NumberFormatException e) { 357 // Whenever the threshold settings are correct, never come here. 358 autoCorrectionThreshold = Float.MAX_VALUE; 359 Log.w(TAG, "Cannot load auto correction threshold setting." 360 + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting 361 + ", autoCorrectionThresholdValues: " 362 + Arrays.toString(autoCorrectionThresholdValues), e); 363 } 364 return autoCorrectionThreshold; 365 } 366} 367