SettingsValues.java revision bea17c49ec23bf0f646cb548445c7756aa50d233
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.Context; 20import android.content.SharedPreferences; 21import android.content.pm.PackageInfo; 22import android.content.res.Configuration; 23import android.content.res.Resources; 24import android.util.Log; 25import android.view.inputmethod.EditorInfo; 26 27import com.android.inputmethod.compat.AppWorkaroundsUtils; 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.utils.AsyncResultHolder; 33import com.android.inputmethod.latin.utils.ResourceUtils; 34import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; 35 36import java.util.Arrays; 37import java.util.Locale; 38 39/** 40 * When you call the constructor of this class, you may want to change the current system locale by 41 * using {@link com.android.inputmethod.latin.utils.RunInLocale}. 42 */ 43public final class SettingsValues { 44 private static final String TAG = SettingsValues.class.getSimpleName(); 45 // "floatMaxValue" and "floatNegativeInfinity" are special marker strings for 46 // Float.NEGATIVE_INFINITE and Float.MAX_VALUE. Currently used for auto-correction settings. 47 private static final String FLOAT_MAX_VALUE_MARKER_STRING = "floatMaxValue"; 48 private static final String FLOAT_NEGATIVE_INFINITY_MARKER_STRING = "floatNegativeInfinity"; 49 private static final int TIMEOUT_TO_GET_TARGET_PACKAGE = 5; // seconds 50 51 // From resources: 52 public final SpacingAndPunctuations mSpacingAndPunctuations; 53 public final int mDelayInMillisecondsToUpdateOldSuggestions; 54 public final long mDoubleSpacePeriodTimeout; 55 56 // From preferences, in the same order as xml/prefs.xml: 57 public final boolean mAutoCap; 58 public final boolean mVibrateOn; 59 public final boolean mSoundOn; 60 public final boolean mKeyPreviewPopupOn; 61 public final boolean mShowsVoiceInputKey; 62 public final boolean mIncludesOtherImesInLanguageSwitchList; 63 public final boolean mShowsLanguageSwitchKey; 64 public final boolean mUseContactsDict; 65 public final boolean mUsePersonalizedDicts; 66 public final boolean mUseDoubleSpacePeriod; 67 public final boolean mBlockPotentiallyOffensive; 68 // Use bigrams to predict the next word when there is no input for it yet 69 public final boolean mBigramPredictionEnabled; 70 public final boolean mGestureInputEnabled; 71 public final boolean mGestureTrailEnabled; 72 public final boolean mGestureFloatingPreviewTextEnabled; 73 public final boolean mSlidingKeyInputPreviewEnabled; 74 public final boolean mPhraseGestureEnabled; 75 public final int mKeyLongpressTimeout; 76 public final Locale mLocale; 77 public final boolean mEnableMetricsLogging; 78 public final boolean mShouldShowUiToAcceptTypedWord; 79 80 // From the input box 81 public final InputAttributes mInputAttributes; 82 83 // Deduced settings 84 public final int mKeypressVibrationDuration; 85 public final float mKeypressSoundVolume; 86 public final int mKeyPreviewPopupDismissDelay; 87 private final boolean mAutoCorrectEnabled; 88 public final float mAutoCorrectionThreshold; 89 public final boolean mAutoCorrectionEnabledPerUserSettings; 90 private final boolean mSuggestionsEnabledPerUserSettings; 91 public final int mDisplayOrientation; 92 private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds; 93 94 // Setting values for additional features 95 public final int[] mAdditionalFeaturesSettingValues = 96 new int[AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE]; 97 98 // TextDecorator 99 public final int mTextHighlightColorForCommitIndicator; 100 public final int mTextHighlightColorForAddToDictionaryIndicator; 101 public final boolean mShowCommitIndicatorOnlyForAutoCorrection; 102 public final boolean mShowCommitIndicatorOnlyForOutOfVocabulary; 103 104 // Debug settings 105 public final boolean mIsInternal; 106 public final int mKeyPreviewShowUpDuration; 107 public final int mKeyPreviewDismissDuration; 108 public final float mKeyPreviewShowUpStartScale; 109 public final float mKeyPreviewDismissEndScale; 110 111 public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res, 112 final InputAttributes inputAttributes) { 113 mLocale = res.getConfiguration().locale; 114 // Get the resources 115 mDelayInMillisecondsToUpdateOldSuggestions = 116 res.getInteger(R.integer.config_delay_in_milliseconds_to_update_old_suggestions); 117 mSpacingAndPunctuations = new SpacingAndPunctuations(res); 118 119 // Store the input attributes 120 if (null == inputAttributes) { 121 mInputAttributes = new InputAttributes( 122 null, false /* isFullscreenMode */, context.getPackageName()); 123 } else { 124 mInputAttributes = inputAttributes; 125 } 126 127 // Get the settings preferences 128 mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); 129 mVibrateOn = Settings.readVibrationEnabled(prefs, res); 130 mSoundOn = Settings.readKeypressSoundEnabled(prefs, res); 131 mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res); 132 mSlidingKeyInputPreviewEnabled = prefs.getBoolean( 133 DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); 134 mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res) 135 && mInputAttributes.mShouldShowVoiceInputKey 136 && SubtypeSwitcher.getInstance().isShortcutImeEnabled(); 137 final String autoCorrectionThresholdRawValue = prefs.getString( 138 Settings.PREF_AUTO_CORRECTION_THRESHOLD, 139 res.getString(R.string.auto_correction_threshold_mode_index_modest)); 140 mIncludesOtherImesInLanguageSwitchList = Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS 141 ? prefs.getBoolean(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false) 142 : true /* forcibly */; 143 mShowsLanguageSwitchKey = Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS 144 ? Settings.readShowsLanguageSwitchKey(prefs) : true /* forcibly */; 145 mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); 146 mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true); 147 mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); 148 mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res); 149 mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res); 150 mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); 151 mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout); 152 mEnableMetricsLogging = prefs.getBoolean(Settings.PREF_ENABLE_METRICS_LOGGING, true); 153 mShouldShowUiToAcceptTypedWord = Settings.HAS_UI_TO_ACCEPT_TYPED_WORD 154 && prefs.getBoolean(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD, true); 155 // Compute other readable settings 156 mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res); 157 mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res); 158 mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); 159 mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); 160 mAutoCorrectionThreshold = readAutoCorrectionThreshold(res, 161 autoCorrectionThresholdRawValue); 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 mPhraseGestureEnabled = Settings.readPhraseGestureEnabled(prefs, res); 167 mAutoCorrectionEnabledPerUserSettings = mAutoCorrectEnabled 168 && !mInputAttributes.mInputTypeNoAutoCorrect; 169 mSuggestionsEnabledPerUserSettings = readSuggestionsEnabled(prefs); 170 AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray( 171 prefs, mAdditionalFeaturesSettingValues); 172 mShowCommitIndicatorOnlyForAutoCorrection = res.getBoolean( 173 R.bool.text_decorator_only_for_auto_correction); 174 mShowCommitIndicatorOnlyForOutOfVocabulary = res.getBoolean( 175 R.bool.text_decorator_only_for_out_of_vocabulary); 176 mTextHighlightColorForCommitIndicator = res.getColor( 177 R.color.text_decorator_commit_indicator_text_highlight_color); 178 mTextHighlightColorForAddToDictionaryIndicator = res.getColor( 179 R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color); 180 mIsInternal = Settings.isInternal(prefs); 181 mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration( 182 prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION, 183 res.getInteger(R.integer.config_key_preview_show_up_duration)); 184 mKeyPreviewDismissDuration = Settings.readKeyPreviewAnimationDuration( 185 prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION, 186 res.getInteger(R.integer.config_key_preview_dismiss_duration)); 187 mKeyPreviewShowUpStartScale = Settings.readKeyPreviewAnimationScale( 188 prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE, 189 ResourceUtils.getFloatFromFraction( 190 res, R.fraction.config_key_preview_show_up_start_scale)); 191 mKeyPreviewDismissEndScale = Settings.readKeyPreviewAnimationScale( 192 prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE, 193 ResourceUtils.getFloatFromFraction( 194 res, R.fraction.config_key_preview_dismiss_end_scale)); 195 mDisplayOrientation = res.getConfiguration().orientation; 196 mAppWorkarounds = new AsyncResultHolder<>(); 197 final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo( 198 mInputAttributes.mTargetApplicationPackageName); 199 if (null != packageInfo) { 200 mAppWorkarounds.set(new AppWorkaroundsUtils(packageInfo)); 201 } else { 202 new TargetPackageInfoGetterTask(context, mAppWorkarounds) 203 .execute(mInputAttributes.mTargetApplicationPackageName); 204 } 205 } 206 207 public boolean isApplicationSpecifiedCompletionsOn() { 208 return mInputAttributes.mApplicationSpecifiedCompletionOn; 209 } 210 211 public boolean needsToLookupSuggestions() { 212 return mInputAttributes.mShouldShowSuggestions 213 && (mAutoCorrectionEnabledPerUserSettings || isSuggestionsEnabledPerUserSettings()); 214 } 215 216 public boolean isSuggestionsEnabledPerUserSettings() { 217 return mSuggestionsEnabledPerUserSettings; 218 } 219 220 public boolean isWordSeparator(final int code) { 221 return mSpacingAndPunctuations.isWordSeparator(code); 222 } 223 224 public boolean isWordConnector(final int code) { 225 return mSpacingAndPunctuations.isWordConnector(code); 226 } 227 228 public boolean isWordCodePoint(final int code) { 229 return Character.isLetter(code) || isWordConnector(code) 230 || Character.COMBINING_SPACING_MARK == Character.getType(code); 231 } 232 233 public boolean isUsuallyPrecededBySpace(final int code) { 234 return mSpacingAndPunctuations.isUsuallyPrecededBySpace(code); 235 } 236 237 public boolean isUsuallyFollowedBySpace(final int code) { 238 return mSpacingAndPunctuations.isUsuallyFollowedBySpace(code); 239 } 240 241 public boolean shouldInsertSpacesAutomatically() { 242 return mInputAttributes.mShouldInsertSpacesAutomatically; 243 } 244 245 public boolean isLanguageSwitchKeyEnabled() { 246 if (!mShowsLanguageSwitchKey) { 247 return false; 248 } 249 final RichInputMethodManager imm = RichInputMethodManager.getInstance(); 250 if (mIncludesOtherImesInLanguageSwitchList) { 251 return imm.hasMultipleEnabledIMEsOrSubtypes(false /* include aux subtypes */); 252 } else { 253 return imm.hasMultipleEnabledSubtypesInThisIme(false /* include aux subtypes */); 254 } 255 } 256 257 public boolean isSameInputType(final EditorInfo editorInfo) { 258 return mInputAttributes.isSameInputType(editorInfo); 259 } 260 261 public boolean hasSameOrientation(final Configuration configuration) { 262 return mDisplayOrientation == configuration.orientation; 263 } 264 265 public boolean isBeforeJellyBean() { 266 final AppWorkaroundsUtils appWorkaroundUtils 267 = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); 268 return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBeforeJellyBean(); 269 } 270 271 public boolean isBrokenByRecorrection() { 272 final AppWorkaroundsUtils appWorkaroundUtils 273 = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); 274 return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBrokenByRecorrection(); 275 } 276 277 private static final String SUGGESTIONS_VISIBILITY_HIDE_VALUE_OBSOLETE = "2"; 278 279 private static boolean readSuggestionsEnabled(final SharedPreferences prefs) { 280 if (prefs.contains(Settings.PREF_SHOW_SUGGESTIONS_SETTING_OBSOLETE)) { 281 final boolean alwaysHide = SUGGESTIONS_VISIBILITY_HIDE_VALUE_OBSOLETE.equals( 282 prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING_OBSOLETE, null)); 283 prefs.edit() 284 .remove(Settings.PREF_SHOW_SUGGESTIONS_SETTING_OBSOLETE) 285 .putBoolean(Settings.PREF_SHOW_SUGGESTIONS, !alwaysHide) 286 .apply(); 287 } 288 return prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, true); 289 } 290 291 private static boolean readBigramPredictionEnabled(final SharedPreferences prefs, 292 final Resources res) { 293 return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( 294 R.bool.config_default_next_word_prediction)); 295 } 296 297 private static float readAutoCorrectionThreshold(final Resources res, 298 final String currentAutoCorrectionSetting) { 299 final String[] autoCorrectionThresholdValues = res.getStringArray( 300 R.array.auto_correction_threshold_values); 301 // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. 302 final float autoCorrectionThreshold; 303 try { 304 final int arrayIndex = Integer.parseInt(currentAutoCorrectionSetting); 305 if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { 306 final String val = autoCorrectionThresholdValues[arrayIndex]; 307 if (FLOAT_MAX_VALUE_MARKER_STRING.equals(val)) { 308 autoCorrectionThreshold = Float.MAX_VALUE; 309 } else if (FLOAT_NEGATIVE_INFINITY_MARKER_STRING.equals(val)) { 310 autoCorrectionThreshold = Float.NEGATIVE_INFINITY; 311 } else { 312 autoCorrectionThreshold = Float.parseFloat(val); 313 } 314 } else { 315 autoCorrectionThreshold = Float.MAX_VALUE; 316 } 317 } catch (final NumberFormatException e) { 318 // Whenever the threshold settings are correct, never come here. 319 Log.w(TAG, "Cannot load auto correction threshold setting." 320 + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting 321 + ", autoCorrectionThresholdValues: " 322 + Arrays.toString(autoCorrectionThresholdValues), e); 323 return Float.MAX_VALUE; 324 } 325 return autoCorrectionThreshold; 326 } 327 328 private static boolean needsToShowVoiceInputKey(final SharedPreferences prefs, 329 final Resources res) { 330 // Migrate preference from {@link Settings#PREF_VOICE_MODE_OBSOLETE} to 331 // {@link Settings#PREF_VOICE_INPUT_KEY}. 332 if (prefs.contains(Settings.PREF_VOICE_MODE_OBSOLETE)) { 333 final String voiceModeMain = res.getString(R.string.voice_mode_main); 334 final String voiceMode = prefs.getString( 335 Settings.PREF_VOICE_MODE_OBSOLETE, voiceModeMain); 336 final boolean shouldShowVoiceInputKey = voiceModeMain.equals(voiceMode); 337 prefs.edit() 338 .putBoolean(Settings.PREF_VOICE_INPUT_KEY, shouldShowVoiceInputKey) 339 // Remove the obsolete preference if exists. 340 .remove(Settings.PREF_VOICE_MODE_OBSOLETE) 341 .apply(); 342 } 343 return prefs.getBoolean(Settings.PREF_VOICE_INPUT_KEY, true); 344 } 345 346 public String dump() { 347 final StringBuilder sb = new StringBuilder("Current settings :"); 348 sb.append("\n mSpacingAndPunctuations = "); 349 sb.append("" + mSpacingAndPunctuations.dump()); 350 sb.append("\n mDelayInMillisecondsToUpdateOldSuggestions = "); 351 sb.append("" + mDelayInMillisecondsToUpdateOldSuggestions); 352 sb.append("\n mAutoCap = "); 353 sb.append("" + mAutoCap); 354 sb.append("\n mVibrateOn = "); 355 sb.append("" + mVibrateOn); 356 sb.append("\n mSoundOn = "); 357 sb.append("" + mSoundOn); 358 sb.append("\n mKeyPreviewPopupOn = "); 359 sb.append("" + mKeyPreviewPopupOn); 360 sb.append("\n mShowsVoiceInputKey = "); 361 sb.append("" + mShowsVoiceInputKey); 362 sb.append("\n mIncludesOtherImesInLanguageSwitchList = "); 363 sb.append("" + mIncludesOtherImesInLanguageSwitchList); 364 sb.append("\n mShowsLanguageSwitchKey = "); 365 sb.append("" + mShowsLanguageSwitchKey); 366 sb.append("\n mUseContactsDict = "); 367 sb.append("" + mUseContactsDict); 368 sb.append("\n mUsePersonalizedDicts = "); 369 sb.append("" + mUsePersonalizedDicts); 370 sb.append("\n mUseDoubleSpacePeriod = "); 371 sb.append("" + mUseDoubleSpacePeriod); 372 sb.append("\n mBlockPotentiallyOffensive = "); 373 sb.append("" + mBlockPotentiallyOffensive); 374 sb.append("\n mBigramPredictionEnabled = "); 375 sb.append("" + mBigramPredictionEnabled); 376 sb.append("\n mGestureInputEnabled = "); 377 sb.append("" + mGestureInputEnabled); 378 sb.append("\n mGestureTrailEnabled = "); 379 sb.append("" + mGestureTrailEnabled); 380 sb.append("\n mGestureFloatingPreviewTextEnabled = "); 381 sb.append("" + mGestureFloatingPreviewTextEnabled); 382 sb.append("\n mSlidingKeyInputPreviewEnabled = "); 383 sb.append("" + mSlidingKeyInputPreviewEnabled); 384 sb.append("\n mPhraseGestureEnabled = "); 385 sb.append("" + mPhraseGestureEnabled); 386 sb.append("\n mKeyLongpressTimeout = "); 387 sb.append("" + mKeyLongpressTimeout); 388 sb.append("\n mLocale = "); 389 sb.append("" + mLocale); 390 sb.append("\n mInputAttributes = "); 391 sb.append("" + mInputAttributes); 392 sb.append("\n mKeypressVibrationDuration = "); 393 sb.append("" + mKeypressVibrationDuration); 394 sb.append("\n mKeypressSoundVolume = "); 395 sb.append("" + mKeypressSoundVolume); 396 sb.append("\n mKeyPreviewPopupDismissDelay = "); 397 sb.append("" + mKeyPreviewPopupDismissDelay); 398 sb.append("\n mAutoCorrectEnabled = "); 399 sb.append("" + mAutoCorrectEnabled); 400 sb.append("\n mAutoCorrectionThreshold = "); 401 sb.append("" + mAutoCorrectionThreshold); 402 sb.append("\n mAutoCorrectionEnabledPerUserSettings = "); 403 sb.append("" + mAutoCorrectionEnabledPerUserSettings); 404 sb.append("\n mSuggestionsEnabledPerUserSettings = "); 405 sb.append("" + mSuggestionsEnabledPerUserSettings); 406 sb.append("\n mDisplayOrientation = "); 407 sb.append("" + mDisplayOrientation); 408 sb.append("\n mAppWorkarounds = "); 409 final AppWorkaroundsUtils awu = mAppWorkarounds.get(null, 0); 410 sb.append("" + (null == awu ? "null" : awu.toString())); 411 sb.append("\n mAdditionalFeaturesSettingValues = "); 412 sb.append("" + Arrays.toString(mAdditionalFeaturesSettingValues)); 413 sb.append("\n mShowCommitIndicatorOnlyForAutoCorrection = "); 414 sb.append("" + mShowCommitIndicatorOnlyForAutoCorrection); 415 sb.append("\n mShowCommitIndicatorOnlyForOutOfVocabulary = "); 416 sb.append("" + mShowCommitIndicatorOnlyForOutOfVocabulary); 417 sb.append("\n mTextHighlightColorForCommitIndicator = "); 418 sb.append("" + mTextHighlightColorForCommitIndicator); 419 sb.append("\n mTextHighlightColorForAddToDictionaryIndicator = "); 420 sb.append("" + mTextHighlightColorForAddToDictionaryIndicator); 421 sb.append("\n mIsInternal = "); 422 sb.append("" + mIsInternal); 423 sb.append("\n mKeyPreviewShowUpDuration = "); 424 sb.append("" + mKeyPreviewShowUpDuration); 425 sb.append("\n mKeyPreviewDismissDuration = "); 426 sb.append("" + mKeyPreviewDismissDuration); 427 sb.append("\n mKeyPreviewShowUpStartScale = "); 428 sb.append("" + mKeyPreviewShowUpStartScale); 429 sb.append("\n mKeyPreviewDismissEndScale = "); 430 sb.append("" + mKeyPreviewDismissEndScale); 431 return sb.toString(); 432 } 433} 434