diff options
Diffstat (limited to 'java/src')
13 files changed, 211 insertions, 63 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 28a22f35c..cf89ef210 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -65,6 +65,7 @@ import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.ResourceUtils; +import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeLocale; @@ -205,8 +206,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private final int mKeyRepeatStartTimeout; private final int mKeyRepeatInterval; - private final int mLongPressKeyTimeout; - private final int mLongPressShiftKeyTimeout; + private final int mLongPressShiftLockTimeout; private final int mIgnoreAltCodeKeyTimeout; private final int mGestureRecognitionUpdateTime; @@ -218,10 +218,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); mKeyRepeatInterval = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_keyRepeatInterval, 0); - mLongPressKeyTimeout = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_longPressKeyTimeout, 0); - mLongPressShiftKeyTimeout = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_longPressShiftKeyTimeout, 0); + mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0); mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( @@ -285,7 +283,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int delay; switch (code) { case Constants.CODE_SHIFT: - delay = mLongPressShiftKeyTimeout; + delay = mLongPressShiftLockTimeout; break; default: delay = 0; @@ -306,15 +304,17 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int delay; switch (key.mCode) { case Constants.CODE_SHIFT: - delay = mLongPressShiftKeyTimeout; + delay = mLongPressShiftLockTimeout; break; default: + final int longpressTimeout = + Settings.getInstance().getCurrent().mKeyLongpressTimeout; if (KeyboardSwitcher.getInstance().isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols // mode key. - delay = mLongPressKeyTimeout * 3; + delay = longpressTimeout * 3; } else { - delay = mLongPressKeyTimeout; + delay = longpressTimeout; } break; } @@ -1371,7 +1371,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private String layoutLanguageOnSpacebar(final Paint paint, final InputMethodSubtype subtype, final int width) { // Choose appropriate language name to fit into the width. - final String fullText = getFullDisplayName(subtype, getResources()); + final String fullText = getFullDisplayName(subtype); if (fitsTextIntoWidth(width, fullText, paint)) { return fullText; } @@ -1445,12 +1445,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // zz azerty T AZERTY AZERTY // Get InputMethodSubtype's full display name in its locale. - static String getFullDisplayName(final InputMethodSubtype subtype, final Resources res) { + static String getFullDisplayName(final InputMethodSubtype subtype) { if (SubtypeLocale.isNoLanguage(subtype)) { return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); } - return SubtypeLocale.getSubtypeDisplayName(subtype, res); + return SubtypeLocale.getSubtypeDisplayName(subtype); } // Get InputMethodSubtype's short display name in its locale. diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java index 0954a7a5d..28655a930 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java @@ -157,6 +157,7 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { */ protected void updatePreviewPosition() { if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) { + getDrawingView().invalidate(); return; } final String text = mSuggestedWords.getWord(0); diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index 9e5e18353..a56c78bcd 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -103,7 +103,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { if (DEBUG_SUBTYPE_ID) { android.util.Log.d(TAG, String.format("%-6s 0x%08x %11d %s", subtype.getLocale(), subtype.hashCode(), subtype.hashCode(), - SubtypeLocale.getSubtypeDisplayName(subtype, context.getResources()))); + SubtypeLocale.getSubtypeDisplayName(subtype))); } if (subtype.containsExtraValueKey(ASCII_CAPABLE)) { items.add(createItem(context, subtype.getLocale())); @@ -205,8 +205,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { setDialogTitle(R.string.add_style); setKey(KEY_NEW_SUBTYPE); } else { - final String displayName = SubtypeLocale.getSubtypeDisplayName( - subtype, getContext().getResources()); + final String displayName = SubtypeLocale.getSubtypeDisplayName(subtype); setTitle(displayName); setDialogTitle(displayName); setKey(KEY_PREFIX + subtype.getLocale() + "_" @@ -498,7 +497,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { final Context context = getActivity(); final Resources res = context.getResources(); final String message = res.getString(R.string.custom_input_style_already_exists, - SubtypeLocale.getSubtypeDisplayName(subtype, res)); + SubtypeLocale.getSubtypeDisplayName(subtype)); Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index fc9953ac0..70eb6e657 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1647,7 +1647,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mExpectingUpdateSelection = true; mConnection.endBatchEdit(); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0); + ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords); } // Space state must be updated before calling updateShiftState mSpaceState = SPACE_STATE_PHANTOM; @@ -2123,8 +2123,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer); } if (ProductionFlag.IS_EXPERIMENTAL) { + final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, - separatorString, mWordComposer.isBatchMode()); + separatorString, mWordComposer.isBatchMode(), suggestedWords); } mExpectingUpdateSelection = true; commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index aa705da56..408ea4a49 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -55,6 +55,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings"; public static final String PREF_GESTURE_INPUT = "gesture_input"; + public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; public static final String PREF_KEYPRESS_SOUND_VOLUME = @@ -175,6 +176,16 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); } + public static int readKeyLongpressTimeout(final SharedPreferences prefs, + final Resources res) { + final int ms = prefs.getInt(PREF_KEY_LONGPRESS_TIMEOUT, -1); + return (ms >= 0) ? ms : readDefaultKeyLongpressTimeout(res); + } + + public static int readDefaultKeyLongpressTimeout(final Resources res) { + return res.getInteger(R.integer.config_default_longpress_key_timeout); + } + public static int readKeypressVibrationDuration(final SharedPreferences prefs, final Resources res) { final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1); diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java index afe6f3594..3ba24fb65 100644 --- a/java/src/com/android/inputmethod/latin/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -164,6 +164,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment getPreferenceScreen().removePreference(gestureTypingSettings); } + setupKeyLongpressTimeoutSettings(prefs, res); setupKeypressVibrationDurationSettings(prefs, res); setupKeypressSoundVolumeSettings(prefs, res); refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); @@ -236,7 +237,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment final StringBuilder styles = new StringBuilder(); for (final InputMethodSubtype subtype : subtypes) { if (styles.length() > 0) styles.append(", "); - styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res)); + styles.append(SubtypeLocale.getSubtypeDisplayName(subtype)); } customInputStyles.setSummary(styles); } @@ -298,6 +299,34 @@ public final class SettingsFragment extends InputMethodSettingsFragment }); } + private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp, + final Resources res) { + final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( + Settings.PREF_KEY_LONGPRESS_TIMEOUT); + if (pref == null) { + return; + } + pref.setInterface(new SeekBarDialogPreference.ValueProxy() { + @Override + public void writeValue(final int value, final String key) { + sp.edit().putInt(key, value).apply(); + } + + @Override + public int readValue(final String key) { + return Settings.readKeyLongpressTimeout(sp, res); + } + + @Override + public int readDefaultValue(final String key) { + return Settings.readDefaultKeyLongpressTimeout(res); + } + + @Override + public void feedbackValue(final int value) {} + }); + } + private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) { final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( Settings.PREF_KEYPRESS_SOUND_VOLUME); diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index d6556d617..29e79e4cc 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -59,6 +59,7 @@ public final class SettingsValues { public final boolean mGestureInputEnabled; public final boolean mGesturePreviewTrailEnabled; public final boolean mGestureFloatingPreviewTextEnabled; + public final int mKeyLongpressTimeout; // From the input box public final InputAttributes mInputAttributes; @@ -121,6 +122,7 @@ public final class SettingsValues { mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); // Compute other readable settings + mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res); mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res); mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index 370a6594b..068c34ed6 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -42,6 +42,7 @@ public final class SubtypeLocale { public static final int UNKNOWN_KEYBOARD_LAYOUT = R.string.subtype_generic; private static boolean sInitialized = false; + private static Resources sResources; private static String[] sPredefinedKeyboardLayoutSet; // Keyboard layout to its display name map. private static final HashMap<String, String> sKeyboardLayoutToDisplayNameMap = @@ -71,10 +72,11 @@ public final class SubtypeLocale { } // Note that this initialization method can be called multiple times. - public static synchronized void init(Context context) { + public static synchronized void init(final Context context) { if (sInitialized) return; final Resources res = context.getResources(); + sResources = res; final String[] predefinedLayoutSet = res.getStringArray(R.array.predefined_layouts); sPredefinedKeyboardLayoutSet = predefinedLayoutSet; @@ -121,15 +123,15 @@ public final class SubtypeLocale { return sPredefinedKeyboardLayoutSet; } - public static boolean isExceptionalLocale(String localeString) { + public static boolean isExceptionalLocale(final String localeString) { return sExceptionalLocaleToWithLayoutNameIdsMap.containsKey(localeString); } - private static final String getNoLanguageLayoutKey(String keyboardLayoutName) { + private static final String getNoLanguageLayoutKey(final String keyboardLayoutName) { return NO_LANGUAGE + "_" + keyboardLayoutName; } - public static int getSubtypeNameId(String localeString, String keyboardLayoutName) { + public static int getSubtypeNameId(final String localeString, final String keyboardLayoutName) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && isExceptionalLocale(localeString)) { return sExceptionalLocaleToWithLayoutNameIdsMap.get(localeString); @@ -141,7 +143,7 @@ public final class SubtypeLocale { return nameId == null ? UNKNOWN_KEYBOARD_LAYOUT : nameId; } - public static String getSubtypeLocaleDisplayName(String localeString) { + public static String getSubtypeLocaleDisplayName(final String localeString) { final String exceptionalValue = sExceptionalDisplayNamesMap.get(localeString); if (exceptionalValue != null) { return exceptionalValue; @@ -166,12 +168,17 @@ public final class SubtypeLocale { // en_US azerty T English (US) (AZERTY) // zz azerty T No language (AZERTY) in system locale - public static String getSubtypeDisplayName(final InputMethodSubtype subtype, Resources res) { - final String replacementString = - (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN - && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) - ? subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME) - : getSubtypeLocaleDisplayName(subtype.getLocale()); + private static String getReplacementString(final InputMethodSubtype subtype) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN + && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) { + return subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME); + } else { + return getSubtypeLocaleDisplayName(subtype.getLocale()); + } + } + + public static String getSubtypeDisplayName(final InputMethodSubtype subtype) { + final String replacementString = getReplacementString(subtype); final int nameResId = subtype.getNameResId(); final RunInLocale<String> getSubtypeName = new RunInLocale<String>() { @Override @@ -190,30 +197,30 @@ public final class SubtypeLocale { } }; final Locale locale = isNoLanguage(subtype) - ? res.getConfiguration().locale : getSubtypeLocale(subtype); - return getSubtypeName.runInLocale(res, locale); + ? sResources.getConfiguration().locale : getSubtypeLocale(subtype); + return getSubtypeName.runInLocale(sResources, locale); } - public static boolean isNoLanguage(InputMethodSubtype subtype) { + public static boolean isNoLanguage(final InputMethodSubtype subtype) { final String localeString = subtype.getLocale(); return localeString.equals(NO_LANGUAGE); } - public static Locale getSubtypeLocale(InputMethodSubtype subtype) { + public static Locale getSubtypeLocale(final InputMethodSubtype subtype) { final String localeString = subtype.getLocale(); return LocaleUtils.constructLocaleFromString(localeString); } - public static String getKeyboardLayoutSetDisplayName(InputMethodSubtype subtype) { + public static String getKeyboardLayoutSetDisplayName(final InputMethodSubtype subtype) { final String layoutName = getKeyboardLayoutSetName(subtype); return getKeyboardLayoutSetDisplayName(layoutName); } - public static String getKeyboardLayoutSetDisplayName(String layoutName) { + public static String getKeyboardLayoutSetDisplayName(final String layoutName) { return sKeyboardLayoutToDisplayNameMap.get(layoutName); } - public static String getKeyboardLayoutSetName(InputMethodSubtype subtype) { + public static String getKeyboardLayoutSetName(final InputMethodSubtype subtype) { String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET); if (keyboardLayoutSet == null) { // This subtype doesn't have a keyboardLayoutSet extra value, so lookup its keyboard diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index eb0ec3990..2f9e34ff1 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -151,8 +151,7 @@ public final class SubtypeSwitcher { // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. public void onSubtypeChanged(final InputMethodSubtype newSubtype) { if (DBG) { - Log.w(TAG, "onSubtypeChanged: " + SubtypeLocale.getSubtypeDisplayName( - newSubtype, mResources)); + Log.w(TAG, "onSubtypeChanged: " + SubtypeLocale.getSubtypeDisplayName(newSubtype)); } final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype); diff --git a/java/src/com/android/inputmethod/research/FixedLogBuffer.java b/java/src/com/android/inputmethod/research/FixedLogBuffer.java index 73f284a73..78dc59562 100644 --- a/java/src/com/android/inputmethod/research/FixedLogBuffer.java +++ b/java/src/com/android/inputmethod/research/FixedLogBuffer.java @@ -61,7 +61,7 @@ public class FixedLogBuffer extends LogBuffer { */ @Override public void shiftIn(final LogUnit newLogUnit) { - if (newLogUnit.getWord() == null) { + if (!newLogUnit.hasWord()) { // This LogUnit isn't a word, so it doesn't count toward the word-limit. super.shiftIn(newLogUnit); return; @@ -153,8 +153,7 @@ public class FixedLogBuffer extends LogBuffer { for (int i = 0; i < length && n > 0; i++) { final LogUnit logUnit = logUnits.get(i); list.add(logUnit); - final String word = logUnit.getWord(); - if (word != null) { + if (logUnit.hasWord()) { n--; } } diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java index 715000d28..638b7d9d4 100644 --- a/java/src/com/android/inputmethod/research/LogUnit.java +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -17,6 +17,7 @@ package com.android.inputmethod.research; import android.content.SharedPreferences; +import android.text.TextUtils; import android.util.JsonWriter; import android.util.Log; import android.view.MotionEvent; @@ -57,16 +58,32 @@ import java.util.Map; // Assume that mTimeList is sorted in increasing order. Do not insert null values into // mTimeList. private final ArrayList<Long> mTimeList; + // Word that this LogUnit generates. Should be null if the LogUnit does not generate a genuine + // word (i.e. separators alone do not count as a word). Should never be empty. private String mWord; private boolean mMayContainDigit; private boolean mIsPartOfMegaword; private boolean mContainsCorrection; + // mCorrectionType indicates whether the word was corrected at all, and if so, whether it was + // to a different word or just a "typo" correction. It is considered a "typo" if the final + // word was listed in the suggestions available the first time the word was gestured or + // tapped. + private int mCorrectionType; + public static final int CORRECTIONTYPE_NO_CORRECTION = 0; + public static final int CORRECTIONTYPE_CORRECTION = 1; + public static final int CORRECTIONTYPE_DIFFERENT_WORD = 2; + public static final int CORRECTIONTYPE_TYPO = 3; + + private SuggestedWords mSuggestedWords; + public LogUnit() { mLogStatementList = new ArrayList<LogStatement>(); mValuesList = new ArrayList<Object[]>(); mTimeList = new ArrayList<Long>(); mIsPartOfMegaword = false; + mCorrectionType = CORRECTIONTYPE_NO_CORRECTION; + mSuggestedWords = null; } private LogUnit(final ArrayList<LogStatement> logStatementList, @@ -77,6 +94,8 @@ import java.util.Map; mValuesList = valuesList; mTimeList = timeList; mIsPartOfMegaword = isPartOfMegaword; + mCorrectionType = CORRECTIONTYPE_NO_CORRECTION; + mSuggestedWords = null; } private static final Object[] NULL_VALUES = new Object[0]; @@ -167,6 +186,7 @@ import java.util.Map; private static final String UPTIME_KEY = "_ut"; private static final String EVENT_TYPE_KEY = "_ty"; private static final String WORD_KEY = "_wo"; + private static final String CORRECTION_TYPE_KEY = "_corType"; private static final String LOG_UNIT_BEGIN_KEY = "logUnitStart"; private static final String LOG_UNIT_END_KEY = "logUnitEnd"; @@ -177,6 +197,7 @@ import java.util.Map; jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis()); if (canIncludePrivateData) { jsonWriter.name(WORD_KEY).value(getWord()); + jsonWriter.name(CORRECTION_TYPE_KEY).value(getCorrectionType()); } jsonWriter.name(EVENT_TYPE_KEY).value(LOG_UNIT_BEGIN_KEY); jsonWriter.endObject(); @@ -254,7 +275,33 @@ import java.util.Map; return true; } - public void setWord(String word) { + /** + * Mark the current logUnit as containing data to generate {@code word}. + * + * If {@code setWord()} was previously called for this LogUnit, then the method will try to + * determine what kind of correction it is, and update its internal state of the correctionType + * accordingly. + * + * @param word The word this LogUnit generates. Caller should not pass null or the empty + * string. + */ + public void setWord(final String word) { + if (hasWord()) { + // The word was already set once, and it is now being changed. See if the new word + // is close to the old word. If so, then the change is probably a typo correction. + // If not, the user may have decided to enter a different word, so flag it. + if (mSuggestedWords != null) { + if (isInSuggestedWords(word, mSuggestedWords)) { + mCorrectionType = CORRECTIONTYPE_TYPO; + } else { + mCorrectionType = CORRECTIONTYPE_DIFFERENT_WORD; + } + } else { + // No suggested words, so it's not clear whether it's a typo or different word. + // Mark it as a generic correction. + mCorrectionType = CORRECTIONTYPE_CORRECTION; + } + } mWord = word; } @@ -263,7 +310,7 @@ import java.util.Map; } public boolean hasWord() { - return mWord != null; + return mWord != null && !TextUtils.isEmpty(mWord.trim()); } public void setMayContainDigit() { @@ -282,6 +329,14 @@ import java.util.Map; return mContainsCorrection; } + public void setCorrectionType(final int correctionType) { + mCorrectionType = correctionType; + } + + public int getCorrectionType() { + return mCorrectionType; + } + public boolean isEmpty() { return mLogStatementList.isEmpty(); } @@ -328,8 +383,43 @@ import java.util.Map; mValuesList.addAll(logUnit.mValuesList); mTimeList.addAll(logUnit.mTimeList); mWord = null; + if (logUnit.mWord != null) { + setWord(logUnit.mWord); + } mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit; mContainsCorrection = mContainsCorrection || logUnit.mContainsCorrection; mIsPartOfMegaword = false; } + + public SuggestedWords getSuggestions() { + return mSuggestedWords; + } + + /** + * Initialize the suggestions. + * + * Once set to a non-null value, the suggestions may not be changed again. This is to keep + * track of the list of words that are close to the user's initial effort to type the word. + * Only words that are close to the initial effort are considered typo corrections. + */ + public void initializeSuggestions(final SuggestedWords suggestedWords) { + if (mSuggestedWords == null) { + mSuggestedWords = suggestedWords; + } + } + + private static boolean isInSuggestedWords(final String queryWord, + final SuggestedWords suggestedWords) { + if (TextUtils.isEmpty(queryWord)) { + return false; + } + final int size = suggestedWords.size(); + for (int i = 0; i < size; i++) { + final SuggestedWordInfo wordInfo = suggestedWords.getInfo(i); + if (queryWord.equals(wordInfo.mWord)) { + return true; + } + } + return false; + } } diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java index 57d5c41d7..3a87bf1df 100644 --- a/java/src/com/android/inputmethod/research/MainLogBuffer.java +++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java @@ -117,20 +117,19 @@ public abstract class MainLogBuffer extends FixedLogBuffer { if (IS_LOGGING_EVERYTHING) { if (mIsStopping) { return true; - } else { - // Only check that it is the right length. If not, wait for later words to make - // complete n-grams. - int numWordsInLogUnitList = 0; - final int length = logUnits.size(); - for (int i = 0; i < length; i++) { - final LogUnit logUnit = logUnits.get(i); - final String word = logUnit.getWord(); - if (word != null) { - numWordsInLogUnitList++; - } + } + // Only check that it is the right length. If not, wait for later words to make + // complete n-grams. + int numWordsInLogUnitList = 0; + final int length = logUnits.size(); + for (int i = 0; i < length; i++) { + final LogUnit logUnit = logUnits.get(i); + final String word = logUnit.getWord(); + if (word != null) { + numWordsInLogUnitList++; } - return numWordsInLogUnitList >= minNGramSize; } + return numWordsInLogUnitList >= minNGramSize; } // Check that we are not sampling too frequently. Having sampled recently might disclose @@ -157,14 +156,14 @@ public abstract class MainLogBuffer extends FixedLogBuffer { final int length = logUnits.size(); for (int i = 0; i < length; i++) { final LogUnit logUnit = logUnits.get(i); - final String word = logUnit.getWord(); - if (word == null) { + if (!logUnit.hasWord()) { // Digits outside words are a privacy threat. if (logUnit.mayContainDigit()) { return false; } } else { numWordsInLogUnitList++; + final String word = logUnit.getWord(); // Words not in the dictionary are a privacy threat. if (ResearchLogger.hasLetters(word) && !(dictionary.isValidWord(word))) { if (DEBUG) { diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 2da571d5a..dbf2d2982 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -785,6 +785,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mCurrentLogUnit.setContainsCorrection(); } + private void setCurrentLogUnitCorrectionType(final int correctionType) { + mCurrentLogUnit.setCorrectionType(correctionType); + } + /* package for test */ void commitCurrentLogUnit() { if (DEBUG) { Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ? @@ -1234,13 +1238,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang "suggestion", "x", "y"); public static void latinIME_pickSuggestionManually(final String replacedWord, final int index, final String suggestion, final boolean isBatchMode) { - final String scrubbedWord = scrubDigitsFromString(suggestion); final ResearchLogger researchLogger = getInstance(); + if (!replacedWord.equals(suggestion.toString())) { + // The user choose something other than what was already there. + researchLogger.setCurrentLogUnitContainsCorrection(); + researchLogger.setCurrentLogUnitCorrectionType(LogUnit.CORRECTIONTYPE_TYPO); + } + final String scrubbedWord = scrubDigitsFromString(suggestion); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PICKSUGGESTIONMANUALLY, scrubDigitsFromString(replacedWord), index, suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); - researchLogger.setCurrentLogUnitContainsCorrection(); researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); researchLogger.mStatistics.recordManualSuggestion(SystemClock.uptimeMillis()); } @@ -1530,10 +1538,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new LogStatement("LatinIMECommitCurrentAutoCorrection", true, true, "typedWord", "autoCorrection", "separatorString"); public static void latinIme_commitCurrentAutoCorrection(final String typedWord, - final String autoCorrection, final String separatorString, final boolean isBatchMode) { + final String autoCorrection, final String separatorString, final boolean isBatchMode, + final SuggestedWords suggestedWords) { final String scrubbedTypedWord = scrubDigitsFromString(typedWord); final String scrubbedAutoCorrection = scrubDigitsFromString(autoCorrection); final ResearchLogger researchLogger = getInstance(); + researchLogger.mCurrentLogUnit.initializeSuggestions(suggestedWords); researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE, isBatchMode); @@ -1731,10 +1741,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new LogStatement("LatinIMEOnEndBatchInput", true, false, "enteredText", "enteredWordPos"); public static void latinIME_onEndBatchInput(final CharSequence enteredText, - final int enteredWordPos) { + final int enteredWordPos, final SuggestedWords suggestedWords) { final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText, enteredWordPos); + researchLogger.mCurrentLogUnit.initializeSuggestions(suggestedWords); researchLogger.mStatistics.recordGestureInput(enteredText.length(), SystemClock.uptimeMillis()); } |