SettingsValues.java revision a61b7245b030395451b4c42ec218a946aa95e030
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 // Debug settings 99 public final boolean mIsInternal; 100 public final int mKeyPreviewShowUpDuration; 101 public final int mKeyPreviewDismissDuration; 102 public final float mKeyPreviewShowUpStartScale; 103 public final float mKeyPreviewDismissEndScale; 104 105 public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res, 106 final InputAttributes inputAttributes) { 107 mLocale = res.getConfiguration().locale; 108 // Get the resources 109 mDelayInMillisecondsToUpdateOldSuggestions = 110 res.getInteger(R.integer.config_delay_in_milliseconds_to_update_old_suggestions); 111 mSpacingAndPunctuations = new SpacingAndPunctuations(res); 112 113 // Store the input attributes 114 if (null == inputAttributes) { 115 mInputAttributes = new InputAttributes( 116 null, false /* isFullscreenMode */, context.getPackageName()); 117 } else { 118 mInputAttributes = inputAttributes; 119 } 120 121 // Get the settings preferences 122 mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); 123 mVibrateOn = Settings.readVibrationEnabled(prefs, res); 124 mSoundOn = Settings.readKeypressSoundEnabled(prefs, res); 125 mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res); 126 mSlidingKeyInputPreviewEnabled = prefs.getBoolean( 127 DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); 128 mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res) 129 && mInputAttributes.mShouldShowVoiceInputKey 130 && SubtypeSwitcher.getInstance().isShortcutImeEnabled(); 131 final String autoCorrectionThresholdRawValue = prefs.getString( 132 Settings.PREF_AUTO_CORRECTION_THRESHOLD, 133 res.getString(R.string.auto_correction_threshold_mode_index_modest)); 134 mIncludesOtherImesInLanguageSwitchList = Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS 135 ? prefs.getBoolean(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false) 136 : true /* forcibly */; 137 mShowsLanguageSwitchKey = Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS 138 ? Settings.readShowsLanguageSwitchKey(prefs) : true /* forcibly */; 139 mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); 140 mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true); 141 mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); 142 mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res); 143 mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res); 144 mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); 145 mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout); 146 mEnableMetricsLogging = prefs.getBoolean(Settings.PREF_ENABLE_METRICS_LOGGING, true); 147 mShouldShowUiToAcceptTypedWord = Settings.HAS_UI_TO_ACCEPT_TYPED_WORD 148 && prefs.getBoolean(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD, true); 149 // Compute other readable settings 150 mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res); 151 mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res); 152 mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); 153 mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); 154 mAutoCorrectionThreshold = readAutoCorrectionThreshold(res, 155 autoCorrectionThresholdRawValue); 156 mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res); 157 mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); 158 mGestureFloatingPreviewTextEnabled = prefs.getBoolean( 159 Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); 160 mPhraseGestureEnabled = Settings.readPhraseGestureEnabled(prefs, res); 161 mAutoCorrectionEnabledPerUserSettings = mAutoCorrectEnabled 162 && !mInputAttributes.mInputTypeNoAutoCorrect; 163 mSuggestionsEnabledPerUserSettings = readSuggestionsEnabled(prefs); 164 AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray( 165 prefs, mAdditionalFeaturesSettingValues); 166 mIsInternal = Settings.isInternal(prefs); 167 mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration( 168 prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION, 169 res.getInteger(R.integer.config_key_preview_show_up_duration)); 170 mKeyPreviewDismissDuration = Settings.readKeyPreviewAnimationDuration( 171 prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION, 172 res.getInteger(R.integer.config_key_preview_dismiss_duration)); 173 mKeyPreviewShowUpStartScale = Settings.readKeyPreviewAnimationScale( 174 prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE, 175 ResourceUtils.getFloatFromFraction( 176 res, R.fraction.config_key_preview_show_up_start_scale)); 177 mKeyPreviewDismissEndScale = Settings.readKeyPreviewAnimationScale( 178 prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE, 179 ResourceUtils.getFloatFromFraction( 180 res, R.fraction.config_key_preview_dismiss_end_scale)); 181 mDisplayOrientation = res.getConfiguration().orientation; 182 mAppWorkarounds = new AsyncResultHolder<>(); 183 final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo( 184 mInputAttributes.mTargetApplicationPackageName); 185 if (null != packageInfo) { 186 mAppWorkarounds.set(new AppWorkaroundsUtils(packageInfo)); 187 } else { 188 new TargetPackageInfoGetterTask(context, mAppWorkarounds) 189 .execute(mInputAttributes.mTargetApplicationPackageName); 190 } 191 } 192 193 public boolean isApplicationSpecifiedCompletionsOn() { 194 return mInputAttributes.mApplicationSpecifiedCompletionOn; 195 } 196 197 public boolean needsToLookupSuggestions() { 198 return mInputAttributes.mShouldShowSuggestions 199 && (mAutoCorrectionEnabledPerUserSettings || isSuggestionsEnabledPerUserSettings()); 200 } 201 202 public boolean isSuggestionsEnabledPerUserSettings() { 203 return mSuggestionsEnabledPerUserSettings; 204 } 205 206 public boolean isWordSeparator(final int code) { 207 return mSpacingAndPunctuations.isWordSeparator(code); 208 } 209 210 public boolean isWordConnector(final int code) { 211 return mSpacingAndPunctuations.isWordConnector(code); 212 } 213 214 public boolean isWordCodePoint(final int code) { 215 return Character.isLetter(code) || isWordConnector(code) 216 || Character.COMBINING_SPACING_MARK == Character.getType(code); 217 } 218 219 public boolean isUsuallyPrecededBySpace(final int code) { 220 return mSpacingAndPunctuations.isUsuallyPrecededBySpace(code); 221 } 222 223 public boolean isUsuallyFollowedBySpace(final int code) { 224 return mSpacingAndPunctuations.isUsuallyFollowedBySpace(code); 225 } 226 227 public boolean shouldInsertSpacesAutomatically() { 228 return mInputAttributes.mShouldInsertSpacesAutomatically; 229 } 230 231 public boolean isLanguageSwitchKeyEnabled() { 232 if (!mShowsLanguageSwitchKey) { 233 return false; 234 } 235 final RichInputMethodManager imm = RichInputMethodManager.getInstance(); 236 if (mIncludesOtherImesInLanguageSwitchList) { 237 return imm.hasMultipleEnabledIMEsOrSubtypes(false /* include aux subtypes */); 238 } else { 239 return imm.hasMultipleEnabledSubtypesInThisIme(false /* include aux subtypes */); 240 } 241 } 242 243 public boolean isSameInputType(final EditorInfo editorInfo) { 244 return mInputAttributes.isSameInputType(editorInfo); 245 } 246 247 public boolean hasSameOrientation(final Configuration configuration) { 248 return mDisplayOrientation == configuration.orientation; 249 } 250 251 public boolean isBeforeJellyBean() { 252 final AppWorkaroundsUtils appWorkaroundUtils 253 = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); 254 return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBeforeJellyBean(); 255 } 256 257 public boolean isBrokenByRecorrection() { 258 final AppWorkaroundsUtils appWorkaroundUtils 259 = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); 260 return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBrokenByRecorrection(); 261 } 262 263 private static final String SUGGESTIONS_VISIBILITY_HIDE_VALUE_OBSOLETE = "2"; 264 265 private static boolean readSuggestionsEnabled(final SharedPreferences prefs) { 266 if (prefs.contains(Settings.PREF_SHOW_SUGGESTIONS_SETTING_OBSOLETE)) { 267 final boolean alwaysHide = SUGGESTIONS_VISIBILITY_HIDE_VALUE_OBSOLETE.equals( 268 prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING_OBSOLETE, null)); 269 prefs.edit() 270 .remove(Settings.PREF_SHOW_SUGGESTIONS_SETTING_OBSOLETE) 271 .putBoolean(Settings.PREF_SHOW_SUGGESTIONS, !alwaysHide) 272 .apply(); 273 } 274 return prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, true); 275 } 276 277 private static boolean readBigramPredictionEnabled(final SharedPreferences prefs, 278 final Resources res) { 279 return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( 280 R.bool.config_default_next_word_prediction)); 281 } 282 283 private static float readAutoCorrectionThreshold(final Resources res, 284 final String currentAutoCorrectionSetting) { 285 final String[] autoCorrectionThresholdValues = res.getStringArray( 286 R.array.auto_correction_threshold_values); 287 // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. 288 final float autoCorrectionThreshold; 289 try { 290 final int arrayIndex = Integer.parseInt(currentAutoCorrectionSetting); 291 if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { 292 final String val = autoCorrectionThresholdValues[arrayIndex]; 293 if (FLOAT_MAX_VALUE_MARKER_STRING.equals(val)) { 294 autoCorrectionThreshold = Float.MAX_VALUE; 295 } else if (FLOAT_NEGATIVE_INFINITY_MARKER_STRING.equals(val)) { 296 autoCorrectionThreshold = Float.NEGATIVE_INFINITY; 297 } else { 298 autoCorrectionThreshold = Float.parseFloat(val); 299 } 300 } else { 301 autoCorrectionThreshold = Float.MAX_VALUE; 302 } 303 } catch (final NumberFormatException e) { 304 // Whenever the threshold settings are correct, never come here. 305 Log.w(TAG, "Cannot load auto correction threshold setting." 306 + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting 307 + ", autoCorrectionThresholdValues: " 308 + Arrays.toString(autoCorrectionThresholdValues), e); 309 return Float.MAX_VALUE; 310 } 311 return autoCorrectionThreshold; 312 } 313 314 private static boolean needsToShowVoiceInputKey(final SharedPreferences prefs, 315 final Resources res) { 316 // Migrate preference from {@link Settings#PREF_VOICE_MODE_OBSOLETE} to 317 // {@link Settings#PREF_VOICE_INPUT_KEY}. 318 if (prefs.contains(Settings.PREF_VOICE_MODE_OBSOLETE)) { 319 final String voiceModeMain = res.getString(R.string.voice_mode_main); 320 final String voiceMode = prefs.getString( 321 Settings.PREF_VOICE_MODE_OBSOLETE, voiceModeMain); 322 final boolean shouldShowVoiceInputKey = voiceModeMain.equals(voiceMode); 323 prefs.edit() 324 .putBoolean(Settings.PREF_VOICE_INPUT_KEY, shouldShowVoiceInputKey) 325 // Remove the obsolete preference if exists. 326 .remove(Settings.PREF_VOICE_MODE_OBSOLETE) 327 .apply(); 328 } 329 return prefs.getBoolean(Settings.PREF_VOICE_INPUT_KEY, true); 330 } 331 332 public String dump() { 333 final StringBuilder sb = new StringBuilder("Current settings :"); 334 sb.append("\n mSpacingAndPunctuations = "); 335 sb.append("" + mSpacingAndPunctuations.dump()); 336 sb.append("\n mDelayInMillisecondsToUpdateOldSuggestions = "); 337 sb.append("" + mDelayInMillisecondsToUpdateOldSuggestions); 338 sb.append("\n mAutoCap = "); 339 sb.append("" + mAutoCap); 340 sb.append("\n mVibrateOn = "); 341 sb.append("" + mVibrateOn); 342 sb.append("\n mSoundOn = "); 343 sb.append("" + mSoundOn); 344 sb.append("\n mKeyPreviewPopupOn = "); 345 sb.append("" + mKeyPreviewPopupOn); 346 sb.append("\n mShowsVoiceInputKey = "); 347 sb.append("" + mShowsVoiceInputKey); 348 sb.append("\n mIncludesOtherImesInLanguageSwitchList = "); 349 sb.append("" + mIncludesOtherImesInLanguageSwitchList); 350 sb.append("\n mShowsLanguageSwitchKey = "); 351 sb.append("" + mShowsLanguageSwitchKey); 352 sb.append("\n mUseContactsDict = "); 353 sb.append("" + mUseContactsDict); 354 sb.append("\n mUsePersonalizedDicts = "); 355 sb.append("" + mUsePersonalizedDicts); 356 sb.append("\n mUseDoubleSpacePeriod = "); 357 sb.append("" + mUseDoubleSpacePeriod); 358 sb.append("\n mBlockPotentiallyOffensive = "); 359 sb.append("" + mBlockPotentiallyOffensive); 360 sb.append("\n mBigramPredictionEnabled = "); 361 sb.append("" + mBigramPredictionEnabled); 362 sb.append("\n mGestureInputEnabled = "); 363 sb.append("" + mGestureInputEnabled); 364 sb.append("\n mGestureTrailEnabled = "); 365 sb.append("" + mGestureTrailEnabled); 366 sb.append("\n mGestureFloatingPreviewTextEnabled = "); 367 sb.append("" + mGestureFloatingPreviewTextEnabled); 368 sb.append("\n mSlidingKeyInputPreviewEnabled = "); 369 sb.append("" + mSlidingKeyInputPreviewEnabled); 370 sb.append("\n mPhraseGestureEnabled = "); 371 sb.append("" + mPhraseGestureEnabled); 372 sb.append("\n mKeyLongpressTimeout = "); 373 sb.append("" + mKeyLongpressTimeout); 374 sb.append("\n mLocale = "); 375 sb.append("" + mLocale); 376 sb.append("\n mInputAttributes = "); 377 sb.append("" + mInputAttributes); 378 sb.append("\n mKeypressVibrationDuration = "); 379 sb.append("" + mKeypressVibrationDuration); 380 sb.append("\n mKeypressSoundVolume = "); 381 sb.append("" + mKeypressSoundVolume); 382 sb.append("\n mKeyPreviewPopupDismissDelay = "); 383 sb.append("" + mKeyPreviewPopupDismissDelay); 384 sb.append("\n mAutoCorrectEnabled = "); 385 sb.append("" + mAutoCorrectEnabled); 386 sb.append("\n mAutoCorrectionThreshold = "); 387 sb.append("" + mAutoCorrectionThreshold); 388 sb.append("\n mAutoCorrectionEnabledPerUserSettings = "); 389 sb.append("" + mAutoCorrectionEnabledPerUserSettings); 390 sb.append("\n mSuggestionsEnabledPerUserSettings = "); 391 sb.append("" + mSuggestionsEnabledPerUserSettings); 392 sb.append("\n mDisplayOrientation = "); 393 sb.append("" + mDisplayOrientation); 394 sb.append("\n mAppWorkarounds = "); 395 final AppWorkaroundsUtils awu = mAppWorkarounds.get(null, 0); 396 sb.append("" + (null == awu ? "null" : awu.toString())); 397 sb.append("\n mAdditionalFeaturesSettingValues = "); 398 sb.append("" + Arrays.toString(mAdditionalFeaturesSettingValues)); 399 sb.append("\n mIsInternal = "); 400 sb.append("" + mIsInternal); 401 sb.append("\n mKeyPreviewShowUpDuration = "); 402 sb.append("" + mKeyPreviewShowUpDuration); 403 sb.append("\n mKeyPreviewDismissDuration = "); 404 sb.append("" + mKeyPreviewDismissDuration); 405 sb.append("\n mKeyPreviewShowUpStartScale = "); 406 sb.append("" + mKeyPreviewShowUpStartScale); 407 sb.append("\n mKeyPreviewDismissEndScale = "); 408 sb.append("" + mKeyPreviewDismissEndScale); 409 return sb.toString(); 410 } 411} 412