diff options
Diffstat (limited to 'java/src')
7 files changed, 152 insertions, 50 deletions
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/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/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java index 7f3d1ae6a..f0c51e194 100644 --- a/java/src/com/android/inputmethod/latin/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -41,7 +41,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment private ListPreference mKeyPreviewPopupDismissDelay; // Use bigrams to predict the next word when there is no input for it yet private CheckBoxPreference mBigramPrediction; - private Preference mDebugSettingsPreference; private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { final Preference preference = findPreference(preferenceKey); @@ -50,11 +49,14 @@ public final class SettingsFragment extends InputMethodSettingsFragment } } - private void ensureConsistencyOfAutoCorrectionSettings() { - final String autoCorrectionOff = getResources().getString( - R.string.auto_correction_threshold_mode_index_off); - final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); - mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); + private static void removePreference(final String preferenceKey, final PreferenceGroup parent) { + if (parent == null) { + return; + } + final Preference preference = parent.findPreference(preferenceKey); + if (preference != null) { + parent.removePreference(preference); + } } @Override @@ -84,22 +86,18 @@ public final class SettingsFragment extends InputMethodSettingsFragment final PreferenceGroup generalSettings = (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); - final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); - final PreferenceGroup gestureTypingSettings = - (PreferenceGroup) findPreference(Settings.PREF_GESTURE_SETTINGS); final PreferenceGroup miscSettings = (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); - mDebugSettingsPreference = findPreference(Settings.PREF_DEBUG_SETTINGS); - if (mDebugSettingsPreference != null) { + final Preference debugSettings = findPreference(Settings.PREF_DEBUG_SETTINGS); + if (debugSettings != null) { if (ProductionFlag.IS_INTERNAL) { final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); debugSettingsIntent.setClassName( context.getPackageName(), DebugSettingsActivity.class.getName()); - mDebugSettingsPreference.setIntent(debugSettingsIntent); + debugSettings.setIntent(debugSettingsIntent); } else { - miscSettings.removePreference(mDebugSettingsPreference); + miscSettings.removePreference(debugSettings); } } @@ -112,11 +110,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment final PreferenceGroup advancedSettings = (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { - generalSettings.removePreference(findPreference(Settings.PREF_VIBRATE_ON)); - if (null != advancedSettings) { // Theoretically advancedSettings cannot be null - advancedSettings.removePreference( - findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS)); - } + removePreference(Settings.PREF_VIBRATE_ON, generalSettings); + removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedSettings); } final boolean showKeyPreviewPopupOption = res.getBoolean( @@ -124,10 +119,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment mKeyPreviewPopupDismissDelay = (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); if (!showKeyPreviewPopupOption) { - generalSettings.removePreference(findPreference(Settings.PREF_POPUP_ON)); - if (null != advancedSettings) { // Theoretically advancedSettings cannot be null - advancedSettings.removePreference(mKeyPreviewPopupDismissDelay); - } + removePreference(Settings.PREF_POPUP_ON, generalSettings); + removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedSettings); } else { final String[] entries = new String[] { res.getString(R.string.key_preview_popup_dismiss_no_delay), @@ -148,10 +141,11 @@ public final class SettingsFragment extends InputMethodSettingsFragment setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, Settings.readShowsLanguageSwitchKey(prefs)); + final PreferenceGroup textCorrectionGroup = + (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); final Intent intent = dictionaryLink.getIntent(); - final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); // TODO: The experimental version is not supported by the Dictionary Pack Service yet if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) { @@ -161,7 +155,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment final boolean gestureInputEnabledByBuildConfig = res.getBoolean( R.bool.config_gesture_input_enabled_by_build_config); if (!gestureInputEnabledByBuildConfig) { - getPreferenceScreen().removePreference(gestureTypingSettings); + removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen()); } setupKeyLongpressTimeoutSettings(prefs, res); @@ -219,6 +213,13 @@ public final class SettingsFragment extends InputMethodSettingsFragment refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); } + private void ensureConsistencyOfAutoCorrectionSettings() { + final String autoCorrectionOff = getResources().getString( + R.string.auto_correction_threshold_mode_index_off); + final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); + mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); + } + private void updateShowCorrectionSuggestionsSummary() { mShowCorrectionSuggestionsPreference.setSummary( getResources().getStringArray(R.array.prefs_suggestion_visibilities) 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()); } |