diff options
Diffstat (limited to 'java/src')
18 files changed, 415 insertions, 295 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 1088fdab4..bc9dbc049 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -36,6 +36,7 @@ import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; +import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SettingsValues; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.WordComposer; @@ -181,8 +182,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { keyboardView.setKeyboard(keyboard); mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); keyboardView.setKeyPreviewPopupEnabled( - SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources), - SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); + Settings.readKeyPreviewPopupEnabled(mPrefs, mResources), + Settings.readKeyPreviewPopupDismissDelay(mPrefs, mResources)); keyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean subtypeChanged = (oldKeyboard == null) diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index b7bee3430..63b9ed666 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -146,13 +146,13 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, // Key preview private static final int PREVIEW_ALPHA = 240; private final int mKeyPreviewLayoutId; - private final int mPreviewOffset; - private final int mPreviewHeight; - private final int mPreviewLingerTimeout; + private final int mKeyPreviewOffset; + private final int mKeyPreviewHeight; private final SparseArray<TextView> mKeyPreviewTexts = CollectionUtils.newSparseArray(); protected final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); private boolean mShowKeyPreviewPopup = true; - private int mDelayAfterPreview; + private int mKeyPreviewLingerTimeout; + // Background state set private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { { // STATE_MIDDLE @@ -252,13 +252,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); mKeyBackground = keyboardViewAttr.getDrawable(R.styleable.KeyboardView_keyBackground); mKeyBackground.getPadding(mKeyBackgroundPadding); - mPreviewOffset = keyboardViewAttr.getDimensionPixelOffset( + mKeyPreviewOffset = keyboardViewAttr.getDimensionPixelOffset( R.styleable.KeyboardView_keyPreviewOffset, 0); - mPreviewHeight = keyboardViewAttr.getDimensionPixelSize( + mKeyPreviewHeight = keyboardViewAttr.getDimensionPixelSize( R.styleable.KeyboardView_keyPreviewHeight, 80); - mPreviewLingerTimeout = keyboardViewAttr.getInt( + mKeyPreviewLingerTimeout = keyboardViewAttr.getInt( R.styleable.KeyboardView_keyPreviewLingerTimeout, 0); - mDelayAfterPreview = mPreviewLingerTimeout; mKeyLabelHorizontalPadding = keyboardViewAttr.getDimensionPixelOffset( R.styleable.KeyboardView_keyLabelHorizontalPadding, 0); mKeyHintLetterPadding = keyboardViewAttr.getDimension( @@ -332,7 +331,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, */ public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { mShowKeyPreviewPopup = previewEnabled; - mDelayAfterPreview = delay; + mKeyPreviewLingerTimeout = delay; } /** @@ -820,7 +819,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, @Override public void dismissKeyPreview(final PointerTracker tracker) { - mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); + mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, tracker); } private void addKeyPreview(final TextView keyPreview) { @@ -942,7 +941,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); final int keyDrawWidth = key.getDrawWidth(); final int previewWidth = previewText.getMeasuredWidth(); - final int previewHeight = mPreviewHeight; + final int previewHeight = mKeyPreviewHeight; // The width and height of visible part of the key preview background. The content marker // of the background 9-patch have to cover the visible part of the background. previewParams.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() @@ -951,7 +950,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, - previewText.getPaddingBottom(); // The distance between the top edge of the parent key and the bottom of the visible part // of the key preview background. - previewParams.mPreviewVisibleOffset = mPreviewOffset - previewText.getPaddingBottom(); + previewParams.mPreviewVisibleOffset = mKeyPreviewOffset - previewText.getPaddingBottom(); getLocationInWindow(mOriginCoords); // The key preview is horizontally aligned with the center of the visible part of the // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and @@ -970,7 +969,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy, } // The key preview is placed vertically above the top edge of the parent key with an // arbitrary offset. - final int previewY = key.mY - previewHeight + mPreviewOffset + final int previewY = key.mY - previewHeight + mKeyPreviewOffset + CoordinateUtils.y(mOriginCoords); if (background != null) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java index 84cfb389c..30ca859d3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java @@ -19,7 +19,6 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Rect; @@ -40,7 +39,6 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { private static final class GesturePreviewTextParams { public final int mGesturePreviewTextSize; public final int mGesturePreviewTextColor; - public final int mGesturePreviewTextDimmedColor; public final int mGesturePreviewTextOffset; public final int mGesturePreviewTextHeight; public final int mGesturePreviewColor; @@ -66,7 +64,6 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f); mGesturePreviewRoundRadius = keyboardViewAttr.getDimension( R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f); - mGesturePreviewTextDimmedColor = Color.GRAY; final Paint textPaint = new Paint(); textPaint.setAntiAlias(true); diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index 6ac5a9b94..a7e85e40c 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -400,7 +400,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context); final String prefSubtypes = - SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); + Settings.readPrefAdditionalSubtypes(mPrefs, getResources()); setPrefSubtypes(prefSubtypes, context); mIsAddingNewSubtype = (savedInstanceState != null) @@ -564,19 +564,13 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { @Override public void onPause() { super.onPause(); - final String oldSubtypes = SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); + final String oldSubtypes = Settings.readPrefAdditionalSubtypes(mPrefs, getResources()); final InputMethodSubtype[] subtypes = getSubtypes(); final String prefSubtypes = AdditionalSubtype.createPrefSubtypes(subtypes); if (prefSubtypes.equals(oldSubtypes)) { return; } - - final SharedPreferences.Editor editor = mPrefs.edit(); - try { - editor.putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes); - } finally { - editor.apply(); - } + Settings.writePrefAdditionalSubtypes(mPrefs, prefSubtypes); mRichImm.setAdditionalInputMethodSubtypes(subtypes); } diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 6367156ef..8a1613120 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -102,7 +102,7 @@ public final class AudioAndHapticFeedbackManager { sound = AudioManager.FX_KEYPRESS_STANDARD; break; } - mAudioManager.playSoundEffect(sound, mSettingsValues.mFxVolume); + mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 3b0112b27..f1f50fe8f 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1083,7 +1083,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public boolean onEvaluateFullscreenMode() { // Reread resource value here, because this method is called by framework anytime as needed. final boolean isFullscreenModeAllowed = - SettingsValues.isFullscreenModeAllowed(getResources()); + Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI // implies NO_FULLSCREEN. However, the framework mistakenly does. i.e. NO_EXTRACT_UI @@ -1131,7 +1131,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.getInstance().onWordFinished(typedWord); + ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode()); } } } @@ -1163,7 +1163,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } private void swapSwapperAndSpace() { - CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); + final CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { @@ -1171,7 +1171,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final String text = lastTwo.charAt(1) + " "; mConnection.commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_swapSwapperAndSpace(text); + ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); } mKeyboardSwitcher.updateShiftState(); } @@ -1191,7 +1191,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final String textToInsert = ". "; mConnection.commitText(textToInsert, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert); + ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, + false /* isBatchMode */); } mKeyboardSwitcher.updateShiftState(); return true; @@ -1440,7 +1441,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mConnection.commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onTextInput(text); + ResearchLogger.latinIME_onTextInput(text, false /* isBatchMode */); } mConnection.endBatchEdit(); // Space state must be updated before calling updateShiftState @@ -1665,10 +1666,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final int length = mWordComposer.size(); if (length > 0) { if (mWordComposer.isBatchMode()) { - mWordComposer.reset(); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_handleBackspace_batch(mWordComposer.getTypedWord()); + final String word = mWordComposer.getTypedWord(); + ResearchLogger.latinIME_handleBackspace_batch(word); + ResearchLogger.getInstance().uncommitCurrentLogUnit( + word, false /* dumpCurrentLogUnit */); } + mWordComposer.reset(); } else { mWordComposer.deleteLast(); } @@ -2084,7 +2088,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, - separatorString); + separatorString, mWordComposer.isBatchMode()); } mExpectingUpdateSelection = true; commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, @@ -2118,7 +2122,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction onCodeInput(primaryCode, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_punctuationSuggestion(index, suggestion); + ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, + false /* isBatchMode */); } return; } @@ -2157,7 +2162,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion); + ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, + mWordComposer.isBatchMode()); } mConnection.endBatchEdit(); // Don't allow cancellation of manual pick @@ -2254,6 +2260,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent()); if (null != word) { restartSuggestionsOnWordBeforeCursor(word); + // TODO: Handle the case where the user manually moves the cursor and then backs up over + // a separator. In that case, the current log unit should not be uncommitted. + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().uncommitCurrentLogUnit(word.toString(), + true /* dumpCurrentLogUnit */); + } } } @@ -2297,7 +2309,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord); + ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord, + mWordComposer.isBatchMode()); } // Don't restart suggestion yet. We'll restart if the user deletes the // separator. diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 0d3ebacb1..f7268fc33 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -648,19 +648,20 @@ public final class RichInputConnection { // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0); - if (!". ".equals(textBeforeCursor)) { + final String periodSpace = ". "; + if (!periodSpace.equals(textBeforeCursor)) { // Theoretically we should not be coming here if there isn't ". " before the // cursor, but the application may be changing the text while we are typing, so // anything goes. We should not crash. Log.d(TAG, "Tried to revert double-space combo but we didn't find " - + "\". \" just before the cursor."); + + "\"" + periodSpace + "\" just before the cursor."); return false; } deleteSurroundingText(2, 0); final String doubleSpace = " "; commitText(doubleSpace, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.richInputConnection_revertDoubleSpacePeriod(doubleSpace); + ResearchLogger.richInputConnection_revertDoubleSpacePeriod(); } return true; } @@ -685,7 +686,7 @@ public final class RichInputConnection { final String text = " " + textBeforeCursor.subSequence(0, 1); commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.richInputConnection_revertSwapPunctuation(text); + ResearchLogger.richInputConnection_revertSwapPunctuation(); } return true; } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 637916f76..e39aae958 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -75,7 +75,7 @@ public final class RichInputMethodManager { // Initialize additional subtypes. SubtypeLocale.init(context); - final String prefAdditionalSubtypes = SettingsValues.getPrefAdditionalSubtypes( + final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes( prefs, context.getResources()); final InputMethodSubtype[] additionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray(prefAdditionalSubtypes); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 1d9d85b47..f592a2515 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -23,6 +23,7 @@ import android.preference.PreferenceManager; import com.android.inputmethod.latin.LocaleUtils.RunInLocale; +import java.util.HashMap; import java.util.Locale; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -66,6 +67,11 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; public static final String PREF_DEBUG_SETTINGS = "debug_settings"; + // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead. + // This is being used only for the backward compatibility. + private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = + "pref_suppress_language_switch_key"; + private Resources mRes; private SharedPreferences mPrefs; private Locale mCurrentLocale; @@ -116,4 +122,94 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public SettingsValues getCurrent() { return mSettingsValues; } + + // Accessed from the settings interface, hence public + public static boolean readKeyPreviewPopupEnabled(final SharedPreferences prefs, + final Resources res) { + final boolean showPopupOption = res.getBoolean( + R.bool.config_enable_show_popup_on_keypress_option); + if (!showPopupOption) return res.getBoolean(R.bool.config_default_popup_preview); + return prefs.getBoolean(PREF_POPUP_ON, + res.getBoolean(R.bool.config_default_popup_preview)); + } + + public static int readKeyPreviewPopupDismissDelay(final SharedPreferences prefs, + final Resources res) { + // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here. + return Integer.parseInt(prefs.getString(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(res.getInteger( + R.integer.config_key_preview_linger_timeout)))); + } + + public static boolean readShowsLanguageSwitchKey(final SharedPreferences prefs) { + if (prefs.contains(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { + final boolean suppressLanguageSwitchKey = prefs.getBoolean( + PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); + final SharedPreferences.Editor editor = prefs.edit(); + editor.remove(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY); + editor.putBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, !suppressLanguageSwitchKey); + editor.apply(); + } + return prefs.getBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, true); + } + + public static String readPrefAdditionalSubtypes(final SharedPreferences prefs, + final Resources res) { + final String predefinedPrefSubtypes = AdditionalSubtype.createPrefSubtypes( + res.getStringArray(R.array.predefined_subtypes)); + return prefs.getString(PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes); + } + + public static void writePrefAdditionalSubtypes(final SharedPreferences prefs, + final String prefSubtypes) { + prefs.edit().putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply(); + } + + public static float readKeypressSoundVolume(final SharedPreferences prefs, + final Resources res) { + final float volume = prefs.getFloat(PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + if (volume >= 0) { + return volume; + } + return Float.parseFloat( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); + } + + public static int readVibrationDuration(final SharedPreferences prefs, + final Resources res) { + final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1); + if (ms >= 0) { + return ms; + } + return Integer.parseInt( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); + } + + public static boolean readUsabilityStudyMode(final SharedPreferences prefs) { + // TODO: use mUsabilityStudyMode instead of reading it again here + return prefs.getBoolean(DebugSettings.PREF_USABILITY_STUDY_MODE, true); + } + + public static long readLastUserHistoryWriteTime(final SharedPreferences prefs, + final String locale) { + final String str = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); + final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str); + if (map.containsKey(locale)) { + return map.get(locale); + } + return 0; + } + + public static void writeLastUserHistoryWriteTime(final SharedPreferences prefs, + final String locale) { + final String oldStr = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); + final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr); + map.put(locale, System.currentTimeMillis()); + final String newStr = LocaleUtils.localeAndTimeHashMapToStr(map); + prefs.edit().putString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply(); + } + + public static boolean readUseFullscreenMode(final Resources res) { + return res.getBoolean(R.bool.config_use_fullscreen_mode); + } } diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java index a2980bfa2..507a37b7c 100644 --- a/java/src/com/android/inputmethod/latin/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -145,11 +145,11 @@ public final class SettingsFragment extends InputMethodSettingsFragment mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); } mKeyPreviewPopupDismissDelay.setEnabled( - SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); + Settings.readKeyPreviewPopupEnabled(prefs, res)); } setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, - SettingsValues.showsLanguageSwitchKey(prefs)); + Settings.readShowsLanguageSwitchKey(prefs)); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); @@ -180,7 +180,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment }); mKeypressVibrationDurationSettingsPref.setSummary( res.getString(R.string.settings_keypress_vibration_duration, - SettingsValues.getCurrentVibrationDuration(prefs, res))); + Settings.readVibrationDuration(prefs, res))); } mKeypressSoundVolumeSettingsPref = @@ -229,7 +229,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment prefs.getBoolean(Settings.PREF_POPUP_ON, true)); } else if (key.equals(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY)) { setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, - SettingsValues.showsLanguageSwitchKey(prefs)); + Settings.readShowsLanguageSwitchKey(prefs)); } else if (key.equals(Settings.PREF_GESTURE_INPUT)) { final boolean gestureInputEnabledByConfig = getResources().getBoolean( R.bool.config_gesture_input_enabled_by_build_config); @@ -261,7 +261,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES); final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); final Resources res = getResources(); - final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res); + final String prefSubtype = Settings.readPrefAdditionalSubtypes(prefs, res); final InputMethodSubtype[] subtypes = AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); final StringBuilder styles = new StringBuilder(); @@ -323,7 +323,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment AudioAndHapticFeedbackManager.getInstance().vibrate(ms); } }; - final int currentMs = SettingsValues.getCurrentVibrationDuration(sp, getResources()); + final int currentMs = Settings.readVibrationDuration(sp, getResources()); final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); builder.setTitle(R.string.prefs_keypress_vibration_duration_settings) .setListener(listener) @@ -339,7 +339,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment private static int getCurrentKeyPressSoundVolumePercent(final SharedPreferences sp, final Resources res) { - return (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * PERCENT_FLOAT); + return (int)(Settings.readKeypressSoundVolume(sp, res) * PERCENT_FLOAT); } private void showKeypressSoundVolumeSettingDialog() { diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 39406621c..fac85a8cc 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -27,7 +27,6 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; /** * When you call the constructor of this class, you may want to change the current system locale by @@ -36,19 +35,6 @@ import java.util.HashMap; public final class SettingsValues { private static final String TAG = SettingsValues.class.getSimpleName(); - private static final int SUGGESTION_VISIBILITY_SHOW_VALUE - = R.string.prefs_suggestion_visibility_show_value; - private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE - = R.string.prefs_suggestion_visibility_show_only_portrait_value; - private static final int SUGGESTION_VISIBILITY_HIDE_VALUE - = R.string.prefs_suggestion_visibility_hide_value; - - private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { - SUGGESTION_VISIBILITY_SHOW_VALUE, - SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE, - SUGGESTION_VISIBILITY_HIDE_VALUE - }; - // From resources: public final int mDelayUpdateOldSuggestions; public final String mWeakSpaceStrippers; @@ -86,7 +72,7 @@ public final class SettingsValues { // Deduced settings public final int mKeypressVibrationDuration; - public final float mFxVolume; + public final float mKeypressSoundVolume; public final int mKeyPreviewPopupDismissDelay; private final boolean mAutoCorrectEnabled; public final float mAutoCorrectionThreshold; @@ -129,10 +115,10 @@ public final class SettingsValues { // Get the settings preferences mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); - mVibrateOn = isVibrateOn(prefs, res); + mVibrateOn = readVibrationEnabled(prefs, res); mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); - mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); + mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res); final String voiceModeMain = res.getString(R.string.voice_mode_main); final String voiceModeOff = res.getString(R.string.voice_mode_off); mVoiceMode = prefs.getString(Settings.PREF_VOICE_MODE, voiceModeMain); @@ -140,23 +126,23 @@ public final class SettingsValues { res.getString(R.string.auto_correction_threshold_mode_index_modest)); mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING, res.getString(R.string.prefs_suggestion_visibility_default_value)); - mUsabilityStudyMode = getUsabilityStudyMode(prefs); + mUsabilityStudyMode = Settings.readUsabilityStudyMode(prefs); mIncludesOtherImesInLanguageSwitchList = prefs.getBoolean( Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); - mShowsLanguageSwitchKey = showsLanguageSwitchKey(prefs); + mShowsLanguageSwitchKey = Settings.readShowsLanguageSwitchKey(prefs); mKeyPreviewPopupDismissDelayRawValue = prefs.getString( Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout))); mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); - mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); - mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res); + mAutoCorrectEnabled = readAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); + mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); // Compute other readable settings - mKeypressVibrationDuration = getCurrentVibrationDuration(prefs, res); - mFxVolume = getCurrentKeypressSoundVolume(prefs, res); - mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res); - mAutoCorrectionThreshold = getAutoCorrectionThreshold(res, + mKeypressVibrationDuration = Settings.readVibrationDuration(prefs, res); + mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); + mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); + mAutoCorrectionThreshold = readAutoCorrectionThreshold(res, mAutoCorrectionThresholdRawValue); mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff); mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain); @@ -171,52 +157,6 @@ public final class SettingsValues { mSuggestionVisibility = createSuggestionVisibility(res); } - // Helper functions to create member values. - private static SuggestedWords createSuggestPuncList(final String[] puncs) { - final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList(); - if (puncs != null) { - for (final String puncSpec : puncs) { - puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, - Dictionary.TYPE_HARDCODED)); - } - } - return new SuggestedWords(puncList, - false /* typedWordValid */, - false /* hasAutoCorrectionCandidate */, - true /* isPunctuationSuggestions */, - false /* isObsoleteSuggestions */, - false /* isPrediction */); - } - - private static String createWordSeparators(final String weakSpaceStrippers, - final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators, - final Resources res) { - String wordSeparators = weakSpaceStrippers + weakSpaceSwappers - + res.getString(R.string.phantom_space_promoting_symbols); - for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { - wordSeparators = wordSeparators.replace( - symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); - } - return wordSeparators; - } - - private int createSuggestionVisibility(final Resources res) { - final String suggestionVisiblityStr = mShowSuggestionsSetting; - for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { - if (suggestionVisiblityStr.equals(res.getString(visibility))) { - return visibility; - } - } - throw new RuntimeException("Bug: visibility string is not configured correctly"); - } - - private static boolean isVibrateOn(final SharedPreferences prefs, final Resources res) { - final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator(); - return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, - res.getBoolean(R.bool.config_default_vibration_enabled)); - } - public boolean isApplicationSpecifiedCompletionsOn() { return mInputAttributes.mApplicationSpecifiedCompletionOn; } @@ -262,63 +202,6 @@ public final class SettingsValues { return mInputAttributes.mShouldInsertSpacesAutomatically; } - private static boolean isAutoCorrectEnabled(final Resources res, - final String currentAutoCorrectionSetting) { - final String autoCorrectionOff = res.getString( - R.string.auto_correction_threshold_mode_index_off); - return !currentAutoCorrectionSetting.equals(autoCorrectionOff); - } - - // TODO: Clean up and move public helper methods to Settings class. - // Public to access from KeyboardSwitcher. Should it have access to some - // process-global instance instead? - public static boolean isKeyPreviewPopupEnabled(final SharedPreferences prefs, - final Resources res) { - final boolean showPopupOption = res.getBoolean( - R.bool.config_enable_show_popup_on_keypress_option); - if (!showPopupOption) return res.getBoolean(R.bool.config_default_popup_preview); - return prefs.getBoolean(Settings.PREF_POPUP_ON, - res.getBoolean(R.bool.config_default_popup_preview)); - } - - // Likewise - public static int getKeyPreviewPopupDismissDelay(final SharedPreferences prefs, - final Resources res) { - // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here. - return Integer.parseInt(prefs.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(res.getInteger( - R.integer.config_key_preview_linger_timeout)))); - } - - private static boolean isBigramPredictionEnabled(final SharedPreferences prefs, - final Resources res) { - return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( - R.bool.config_default_next_word_prediction)); - } - - private static float getAutoCorrectionThreshold(final Resources res, - final String currentAutoCorrectionSetting) { - final String[] autoCorrectionThresholdValues = res.getStringArray( - R.array.auto_correction_threshold_values); - // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. - float autoCorrectionThreshold = Float.MAX_VALUE; - try { - final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); - if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { - autoCorrectionThreshold = Float.parseFloat( - autoCorrectionThresholdValues[arrayIndex]); - } - } catch (NumberFormatException e) { - // Whenever the threshold settings are correct, never come here. - autoCorrectionThreshold = Float.MAX_VALUE; - Log.w(TAG, "Cannot load auto correction threshold setting." - + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting - + ", autoCorrectionThresholdValues: " - + Arrays.toString(autoCorrectionThresholdValues)); - } - return autoCorrectionThreshold; - } - public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) { final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; @@ -330,23 +213,6 @@ public final class SettingsValues { return mVoiceKeyOnMain; } - // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead. - // This is being used only for the backward compatibility. - private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = - "pref_suppress_language_switch_key"; - - public static boolean showsLanguageSwitchKey(final SharedPreferences prefs) { - if (prefs.contains(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { - final boolean suppressLanguageSwitchKey = prefs.getBoolean( - PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); - final SharedPreferences.Editor editor = prefs.edit(); - editor.remove(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY); - editor.putBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, !suppressLanguageSwitchKey); - editor.apply(); - } - return prefs.getBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, true); - } - public boolean isLanguageSwitchKeyEnabled() { if (!mShowsLanguageSwitchKey) { return false; @@ -359,65 +225,102 @@ public final class SettingsValues { } } - public static boolean isFullscreenModeAllowed(final Resources res) { - return res.getBoolean(R.bool.config_use_fullscreen_mode); + public boolean isSameInputType(final EditorInfo editorInfo) { + return mInputAttributes.isSameInputType(editorInfo); } - public static String getPrefAdditionalSubtypes(final SharedPreferences prefs, - final Resources res) { - final String predefinedPrefSubtypes = AdditionalSubtype.createPrefSubtypes( - res.getStringArray(R.array.predefined_subtypes)); - return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes); + // Helper functions to create member values. + private static SuggestedWords createSuggestPuncList(final String[] puncs) { + final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList(); + if (puncs != null) { + for (final String puncSpec : puncs) { + puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), + SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, + Dictionary.TYPE_HARDCODED)); + } + } + return new SuggestedWords(puncList, + false /* typedWordValid */, + false /* hasAutoCorrectionCandidate */, + true /* isPunctuationSuggestions */, + false /* isObsoleteSuggestions */, + false /* isPrediction */); } - // Accessed from the settings interface, hence public - public static float getCurrentKeypressSoundVolume(final SharedPreferences prefs, + private static String createWordSeparators(final String weakSpaceStrippers, + final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators, final Resources res) { - final float volume = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); - if (volume >= 0) { - return volume; + String wordSeparators = weakSpaceStrippers + weakSpaceSwappers + + res.getString(R.string.phantom_space_promoting_symbols); + for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { + wordSeparators = wordSeparators.replace( + symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); } - return Float.parseFloat( - ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); + return wordSeparators; } - // Likewise - public static int getCurrentVibrationDuration(final SharedPreferences prefs, - final Resources res) { - final int ms = prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); - if (ms >= 0) { - return ms; + private static final int SUGGESTION_VISIBILITY_SHOW_VALUE = + R.string.prefs_suggestion_visibility_show_value; + private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE = + R.string.prefs_suggestion_visibility_show_only_portrait_value; + private static final int SUGGESTION_VISIBILITY_HIDE_VALUE = + R.string.prefs_suggestion_visibility_hide_value; + private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { + SUGGESTION_VISIBILITY_SHOW_VALUE, + SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE, + SUGGESTION_VISIBILITY_HIDE_VALUE + }; + + private int createSuggestionVisibility(final Resources res) { + final String suggestionVisiblityStr = mShowSuggestionsSetting; + for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { + if (suggestionVisiblityStr.equals(res.getString(visibility))) { + return visibility; + } } - return Integer.parseInt( - ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); + throw new RuntimeException("Bug: visibility string is not configured correctly"); } - // Likewise - public static boolean getUsabilityStudyMode(final SharedPreferences prefs) { - // TODO: use mUsabilityStudyMode instead of reading it again here - return prefs.getBoolean(DebugSettings.PREF_USABILITY_STUDY_MODE, true); + private static boolean readVibrationEnabled(final SharedPreferences prefs, + final Resources res) { + final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator(); + return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, + res.getBoolean(R.bool.config_default_vibration_enabled)); } - public static long getLastUserHistoryWriteTime(final SharedPreferences prefs, - final String locale) { - final String str = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); - final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str); - if (map.containsKey(locale)) { - return map.get(locale); - } - return 0; + private static boolean readAutoCorrectEnabled(final Resources res, + final String currentAutoCorrectionSetting) { + final String autoCorrectionOff = res.getString( + R.string.auto_correction_threshold_mode_index_off); + return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } - public static void setLastUserHistoryWriteTime(final SharedPreferences prefs, - final String locale) { - final String oldStr = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); - final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr); - map.put(locale, System.currentTimeMillis()); - final String newStr = LocaleUtils.localeAndTimeHashMapToStr(map); - prefs.edit().putString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply(); + private static boolean readBigramPredictionEnabled(final SharedPreferences prefs, + final Resources res) { + return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( + R.bool.config_default_next_word_prediction)); } - public boolean isSameInputType(final EditorInfo editorInfo) { - return mInputAttributes.isSameInputType(editorInfo); + private static float readAutoCorrectionThreshold(final Resources res, + final String currentAutoCorrectionSetting) { + final String[] autoCorrectionThresholdValues = res.getStringArray( + R.array.auto_correction_threshold_values); + // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. + float autoCorrectionThreshold = Float.MAX_VALUE; + try { + final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); + if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { + autoCorrectionThreshold = Float.parseFloat( + autoCorrectionThresholdValues[arrayIndex]); + } + } catch (NumberFormatException e) { + // Whenever the threshold settings are correct, never come here. + autoCorrectionThreshold = Float.MAX_VALUE; + Log.w(TAG, "Cannot load auto correction threshold setting." + + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting + + ", autoCorrectionThresholdValues: " + + Arrays.toString(autoCorrectionThresholdValues)); + } + return autoCorrectionThreshold; } } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 31a0f83f1..4c7884836 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -219,7 +219,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary { } catch (InterruptedException e) { } } - final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale); + final long last = Settings.readLastUserHistoryWriteTime(mPrefs, mLocale); final boolean initializing = last == 0; final long now = System.currentTimeMillis(); profTotal = 0; @@ -355,7 +355,7 @@ public final class UserHistoryDictionary extends ExpandableDictionary { } // Save the timestamp after we finish writing the binary dictionary. - SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); + Settings.writeLastUserHistoryWriteTime(mPrefs, mLocale); if (PROFILE_SAVE_RESTORE) { final long diff = System.currentTimeMillis() - now; Log.w(TAG, "PROF: Write User HistoryDictionary: " + mLocale + ", " + diff + "ms."); diff --git a/java/src/com/android/inputmethod/research/FixedLogBuffer.java b/java/src/com/android/inputmethod/research/FixedLogBuffer.java index f3302d856..9613c2db2 100644 --- a/java/src/com/android/inputmethod/research/FixedLogBuffer.java +++ b/java/src/com/android/inputmethod/research/FixedLogBuffer.java @@ -72,6 +72,15 @@ public class FixedLogBuffer extends LogBuffer { mNumActualWords++; // Must be a word, or we wouldn't be here. } + @Override + public LogUnit unshiftIn() { + final LogUnit logUnit = super.unshiftIn(); + if (logUnit != null && logUnit.hasWord()) { + mNumActualWords--; + } + return logUnit; + } + private void shiftOutThroughFirstWord() { final LinkedList<LogUnit> logUnits = getLogUnits(); while (!logUnits.isEmpty()) { diff --git a/java/src/com/android/inputmethod/research/LogBuffer.java b/java/src/com/android/inputmethod/research/LogBuffer.java index 14e8d08a2..9d095f8ad 100644 --- a/java/src/com/android/inputmethod/research/LogBuffer.java +++ b/java/src/com/android/inputmethod/research/LogBuffer.java @@ -46,6 +46,20 @@ public class LogBuffer { mLogUnits.add(logUnit); } + public LogUnit unshiftIn() { + if (mLogUnits.isEmpty()) { + return null; + } + return mLogUnits.removeLast(); + } + + public LogUnit peekLastLogUnit() { + if (mLogUnits.isEmpty()) { + return null; + } + return mLogUnits.peekLast(); + } + public boolean isEmpty() { return mLogUnits.isEmpty(); } diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java index bcb144f5f..ef2c4ea29 100644 --- a/java/src/com/android/inputmethod/research/LogUnit.java +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -240,6 +240,7 @@ import java.util.Map; public LogUnit splitByTime(final long maxTime) { // Assume that mTimeList is in sorted order. final int length = mTimeList.size(); + // TODO: find time by binary search, e.g. using Collections#binarySearch() for (int index = 0; index < length; index++) { if (mTimeList.get(index) > maxTime) { final List<LogStatement> laterLogStatements = @@ -267,4 +268,13 @@ import java.util.Map; } return new LogUnit(); } + + public void append(final LogUnit logUnit) { + mLogStatementList.addAll(logUnit.mLogStatementList); + mValuesList.addAll(logUnit.mValuesList); + mTimeList.addAll(logUnit.mTimeList); + mWord = null; + mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit; + mIsPartOfMegaword = false; + } } diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java index bec21d7e0..898a042d6 100644 --- a/java/src/com/android/inputmethod/research/MainLogBuffer.java +++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java @@ -119,6 +119,7 @@ public class MainLogBuffer extends FixedLogBuffer { // complete buffer contents in detail. final LinkedList<LogUnit> logUnits = getLogUnits(); final int length = logUnits.size(); + int wordsFound = 0; for (int i = 0; i < length; i++) { final LogUnit logUnit = logUnits.get(i); final String word = logUnit.getWord(); @@ -135,9 +136,18 @@ public class MainLogBuffer extends FixedLogBuffer { + ", isValid: " + (dictionary.isValidWord(word))); } return false; + } else { + wordsFound++; } } } + if (wordsFound < N_GRAM_SIZE) { + // Not enough words. Not unsafe, but reject anyway. + if (DEBUG) { + Log.d(TAG, "not enough words"); + } + return false; + } // All checks have passed; this buffer's content can be safely uploaded. return true; } diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java index a6b1b889f..a2356e6a3 100644 --- a/java/src/com/android/inputmethod/research/ResearchLog.java +++ b/java/src/com/android/inputmethod/research/ResearchLog.java @@ -193,6 +193,9 @@ public class ResearchLog { }); } catch (RejectedExecutionException e) { // TODO: Add code to record loss of data, and report. + if (DEBUG) { + Log.d(TAG, "ResearchLog.publish() rejecting scheduled execution"); + } } } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index b1484e696..b61db272c 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -85,7 +85,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String TAG = ResearchLogger.class.getSimpleName(); private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Whether all n-grams should be logged. true will disclose private info. - private static final boolean LOG_EVERYTHING = false + private static final boolean IS_LOGGING_EVERYTHING = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Whether the TextView contents are logged at the end of the session. true will disclose // private info. @@ -105,7 +105,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final boolean IS_SHOWING_INDICATOR = true; // Change the default indicator to something very visible. Currently two red vertical bars on // either side of they keyboard. - private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || LOG_EVERYTHING; + private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || IS_LOGGING_EVERYTHING; public static final int FEEDBACK_WORD_BUFFER_SIZE = 5; // constants related to specific log points @@ -390,11 +390,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (DEBUG) { Log.d(TAG, "stop called"); } + // Commit mCurrentLogUnit before closing. commitCurrentLogUnit(); if (mMainLogBuffer != null) { publishLogBuffer(mMainLogBuffer, mMainResearchLog, - LOG_EVERYTHING /* isIncludingPrivateData */); + IS_LOGGING_EVERYTHING /* isIncludingPrivateData */); mMainResearchLog.close(null /* callback */); mMainLogBuffer = null; } @@ -676,11 +677,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /** * Buffer a research log event, flagging it as privacy-sensitive. */ - private synchronized void enqueueEvent(LogStatement logStatement, Object... values) { + private synchronized void enqueueEvent(final LogStatement logStatement, + final Object... values) { + enqueueEvent(mCurrentLogUnit, logStatement, values); + } + + private synchronized void enqueueEvent(final LogUnit logUnit, final LogStatement logStatement, + final Object... values) { assert values.length == logStatement.mKeys.length; - if (isAllowedToLog()) { + if (isAllowedToLog() && logUnit != null) { final long time = SystemClock.uptimeMillis(); - mCurrentLogUnit.addLogStatement(logStatement, time, values); + logUnit.addLogStatement(logStatement, time, values); } } @@ -695,12 +702,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } if (!mCurrentLogUnit.isEmpty()) { if (mMainLogBuffer != null) { - mMainLogBuffer.shiftIn(mCurrentLogUnit); - if ((mMainLogBuffer.isSafeToLog() || LOG_EVERYTHING) && mMainResearchLog != null) { + if ((mMainLogBuffer.isSafeToLog() || IS_LOGGING_EVERYTHING) + && mMainResearchLog != null) { publishLogBuffer(mMainLogBuffer, mMainResearchLog, true /* isIncludingPrivateData */); mMainLogBuffer.resetWordCounter(); } + mMainLogBuffer.shiftIn(mCurrentLogUnit); } if (mFeedbackLogBuffer != null) { mFeedbackLogBuffer.shiftIn(mCurrentLogUnit); @@ -709,6 +717,50 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + public void uncommitCurrentLogUnit(final String expectedWord, + final boolean dumpCurrentLogUnit) { + // The user has deleted this word and returned to the previous. Check that the word in the + // logUnit matches the expected word. If so, restore the last log unit committed to be the + // current logUnit. I.e., pull out the last LogUnit from all the LogBuffers, and make + // restore it to mCurrentLogUnit so the new edits are captured with the word. Optionally + // dump the contents of mCurrentLogUnit (useful if they contain deletions of the next word + // that should not be reported to protect user privacy) + // + // Note that we don't use mLastLogUnit here, because it only goes one word back and is only + // needed for reverts, which only happen one back. + if (mMainLogBuffer == null) { + return; + } + final LogUnit oldLogUnit = mMainLogBuffer.peekLastLogUnit(); + + // Check that expected word matches. + if (oldLogUnit != null) { + final String oldLogUnitWord = oldLogUnit.getWord(); + if (!oldLogUnitWord.equals(expectedWord)) { + return; + } + } + + // Uncommit, merging if necessary. + mMainLogBuffer.unshiftIn(); + if (oldLogUnit != null && !dumpCurrentLogUnit) { + oldLogUnit.append(mCurrentLogUnit); + mSavedDownEventTime = Long.MAX_VALUE; + } + if (oldLogUnit == null) { + mCurrentLogUnit = new LogUnit(); + } else { + mCurrentLogUnit = oldLogUnit; + } + if (mFeedbackLogBuffer != null) { + mFeedbackLogBuffer.unshiftIn(); + } + if (DEBUG) { + Log.d(TAG, "uncommitCurrentLogUnit back to " + (mCurrentLogUnit.hasWord() + ? ": '" + mCurrentLogUnit.getWord() + "'" : "")); + } + } + private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_OPENING = new LogStatement("logSegmentStart", false, false, "isIncludingPrivateData"); private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_CLOSING = @@ -751,24 +803,26 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * After this operation completes, mCurrentLogUnit will hold any logStatements that happened * after maxTime. */ - private static final LogStatement LOGSTATEMENT_COMMIT_RECORD_SPLIT_WORDS = - new LogStatement("recordSplitWords", true, false); - /* package for test */ void commitCurrentLogUnitAsWord(final String word, final long maxTime) { + /* package for test */ void commitCurrentLogUnitAsWord(final String word, final long maxTime, + final boolean isBatchMode) { + if (word == null) { + return; + } final Dictionary dictionary = getDictionary(); - if (word != null && word.length() > 0 && hasLetters(word)) { + if (word.length() > 0 && hasLetters(word)) { mCurrentLogUnit.setWord(word); final boolean isDictionaryWord = dictionary != null && dictionary.isValidWord(word); mStatistics.recordWordEntered(isDictionaryWord); } final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); - enqueueCommitText(word); + enqueueCommitText(word, isBatchMode); commitCurrentLogUnit(); mCurrentLogUnit = newLogUnit; } - public void onWordFinished(final String word) { - commitCurrentLogUnitAsWord(word, mSavedDownEventTime); + public void onWordFinished(final String word, final boolean isBatchMode) { + commitCurrentLogUnitAsWord(word, mSavedDownEventTime, isBatchMode); mSavedDownEventTime = Long.MAX_VALUE; } @@ -863,7 +917,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Integer.toHexString(editorInfo.inputType), Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, - OUTPUT_FORMAT_VERSION, LOG_EVERYTHING, + OUTPUT_FORMAT_VERSION, IS_LOGGING_EVERYTHING, ProductionFlag.IS_EXPERIMENTAL_DEBUG); } catch (NameNotFoundException e) { e.printStackTrace(); @@ -1060,9 +1114,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: Raw text is added to the TextView. */ - public static void latinIME_onTextInput(final String text) { + public static void latinIME_onTextInput(final String text, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE, isBatchMode); } /** @@ -1074,14 +1128,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new LogStatement("LatinIMEPickSuggestionManually", true, false, "replacedWord", "index", "suggestion", "x", "y"); public static void latinIME_pickSuggestionManually(final String replacedWord, - final int index, final String suggestion) { + final int index, final String suggestion, final boolean isBatchMode) { final String scrubbedWord = scrubDigitsFromString(suggestion); final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PICKSUGGESTIONMANUALLY, scrubDigitsFromString(replacedWord), index, suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); researchLogger.mStatistics.recordManualSuggestion(); } @@ -1093,11 +1147,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final LogStatement LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION = new LogStatement("LatinIMEPunctuationSuggestion", false, false, "index", "suggestion", "x", "y"); - public static void latinIME_punctuationSuggestion(final int index, final String suggestion) { + public static void latinIME_punctuationSuggestion(final int index, final String suggestion, + final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION, index, suggestion, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); - researchLogger.commitCurrentLogUnitAsWord(suggestion, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(suggestion, Long.MAX_VALUE, isBatchMode); } /** @@ -1125,11 +1180,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * if a soft space is inserted after a word. */ private static final LogStatement LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE = - new LogStatement("LatinIMESwapSwapperAndSpace", false, false); - public static void latinIME_swapSwapperAndSpace(final String text) { + new LogStatement("LatinIMESwapSwapperAndSpace", false, false, "originalCharacters", + "charactersAfterSwap"); + public static void latinIME_swapSwapperAndSpace(final CharSequence originalCharacters, + final String charactersAfterSwap) { final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); - researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE); + final LogUnit logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit(); + if (logUnit != null) { + researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE, + originalCharacters, charactersAfterSwap); + } } /** @@ -1137,9 +1197,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: Two spaces have been replaced by period space. */ - public static void latinIME_maybeDoubleSpacePeriod(final String text) { + public static void latinIME_maybeDoubleSpacePeriod(final String text, + final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE, isBatchMode); } /** @@ -1191,12 +1252,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new LogStatement("LatinIMERevertCommit", true, false, "committedWord", "originallyTypedWord"); public static void latinIME_revertCommit(final String committedWord, - final String originallyTypedWord) { + final String originallyTypedWord, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, - originallyTypedWord); + final LogUnit logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit(); + if (originallyTypedWord.length() > 0 && hasLetters(originallyTypedWord)) { + if (logUnit != null) { + logUnit.setWord(originallyTypedWord); + } + } + researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit, + LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord); researchLogger.mStatistics.recordRevertCommit(); - researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode); } /** @@ -1295,9 +1362,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: The IME has reverted ". ", which had previously replaced two typed spaces. */ - public static void richInputConnection_revertDoubleSpacePeriod(final String doubleSpace) { - final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(doubleSpace, Long.MAX_VALUE); + private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_REVERTDOUBLESPACEPERIOD = + new LogStatement("RichInputConnectionRevertDoubleSpacePeriod", false, false); + public static void richInputConnection_revertDoubleSpacePeriod() { + getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_REVERTDOUBLESPACEPERIOD); } /** @@ -1305,9 +1373,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * SystemResponse: The IME has reverted a punctuation swap. */ - public static void richInputConnection_revertSwapPunctuation(final String text) { - final ResearchLogger researchLogger = getInstance(); - researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE); + private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTION_REVERTSWAPPUNCTUATION = + new LogStatement("RichInputConnectionRevertSwapPunctuation", false, false); + public static void richInputConnection_revertSwapPunctuation() { + getInstance().enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTION_REVERTSWAPPUNCTUATION); } /** @@ -1317,16 +1386,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * text input to another word that the user more likely desired to type. */ private static final LogStatement LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION = - new LogStatement("LatinIMECommitCurrentAutoCorrection", true, false, "typedWord", + new LogStatement("LatinIMECommitCurrentAutoCorrection", true, true, "typedWord", "autoCorrection", "separatorString"); public static void latinIme_commitCurrentAutoCorrection(final String typedWord, - final String autoCorrection, final String separatorString) { + final String autoCorrection, final String separatorString, final boolean isBatchMode) { final String scrubbedTypedWord = scrubDigitsFromString(typedWord); final String scrubbedAutoCorrection = scrubDigitsFromString(autoCorrection); final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION, scrubbedTypedWord, scrubbedAutoCorrection, separatorString); - researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE, + isBatchMode); } private boolean isExpectingCommitText = false; @@ -1340,13 +1410,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // add invocations. private static final LogStatement LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT = new LogStatement("LatinIMECommitPartialText", true, false, "newCursorPosition"); - public static void latinIME_commitPartialText(final CharSequence committedWord, - final long lastTimestampOfWordData) { + public static void latinIME_commitPartialText(final String committedWord, + final long lastTimestampOfWordData, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - final String scrubbedWord = scrubDigitsFromString(committedWord.toString()); + final String scrubbedWord = scrubDigitsFromString(committedWord); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData); - researchLogger.mStatistics.recordSplitWords(); + researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData, + isBatchMode); } /** @@ -1357,14 +1427,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang */ private static final LogStatement LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT = new LogStatement("RichInputConnectionCommitText", true, false, "newCursorPosition"); - public static void richInputConnection_commitText(final CharSequence committedWord, - final int newCursorPosition) { + public static void richInputConnection_commitText(final String committedWord, + final int newCursorPosition, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); - final String scrubbedWord = scrubDigitsFromString(committedWord.toString()); + final String scrubbedWord = scrubDigitsFromString(committedWord); if (!researchLogger.isExpectingCommitText) { researchLogger.enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT, newCursorPosition); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE); + researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); } researchLogger.isExpectingCommitText = false; } @@ -1373,9 +1443,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * Shared event for logging committed text. */ private static final LogStatement LOGSTATEMENT_COMMITTEXT = - new LogStatement("CommitText", true, false, "committedText"); - private void enqueueCommitText(final CharSequence word) { - enqueueEvent(LOGSTATEMENT_COMMITTEXT, word); + new LogStatement("CommitText", true, false, "committedText", "isBatchMode"); + private void enqueueCommitText(final String word, final boolean isBatchMode) { + enqueueEvent(LOGSTATEMENT_COMMITTEXT, word, isBatchMode); } /** |