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