Home | History | Annotate | Download | only in settings
      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 
    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 
    227     public boolean isMetricsLoggingEnabled() {
    228         return mEnableMetricsLogging;
    229     }
    230 
    231     public boolean isApplicationSpecifiedCompletionsOn() {
    232         return mInputAttributes.mApplicationSpecifiedCompletionOn;
    233     }
    234 
    235     public boolean needsToLookupSuggestions() {
    236         return mInputAttributes.mShouldShowSuggestions
    237                 && (mAutoCorrectionEnabledPerUserSettings || isSuggestionsEnabledPerUserSettings());
    238     }
    239 
    240     public boolean isSuggestionsEnabledPerUserSettings() {
    241         return mSuggestionsEnabledPerUserSettings;
    242     }
    243 
    244     public boolean isPersonalizationEnabled() {
    245         return mUsePersonalizedDicts;
    246     }
    247 
    248     public boolean isWordSeparator(final int code) {
    249         return mSpacingAndPunctuations.isWordSeparator(code);
    250     }
    251 
    252     public boolean isWordConnector(final int code) {
    253         return mSpacingAndPunctuations.isWordConnector(code);
    254     }
    255 
    256     public boolean isWordCodePoint(final int code) {
    257         return Character.isLetter(code) || isWordConnector(code)
    258                 || Character.COMBINING_SPACING_MARK == Character.getType(code);
    259     }
    260 
    261     public boolean isUsuallyPrecededBySpace(final int code) {
    262         return mSpacingAndPunctuations.isUsuallyPrecededBySpace(code);
    263     }
    264 
    265     public boolean isUsuallyFollowedBySpace(final int code) {
    266         return mSpacingAndPunctuations.isUsuallyFollowedBySpace(code);
    267     }
    268 
    269     public boolean shouldInsertSpacesAutomatically() {
    270         return mInputAttributes.mShouldInsertSpacesAutomatically;
    271     }
    272 
    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 
    284     public boolean isSameInputType(final EditorInfo editorInfo) {
    285         return mInputAttributes.isSameInputType(editorInfo);
    286     }
    287 
    288     public boolean hasSameOrientation(final Configuration configuration) {
    289         return mDisplayOrientation == configuration.orientation;
    290     }
    291 
    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 
    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 
    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 
    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 
    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 
    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 
    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