From edea47ff2e901d02b381bf88aa6cb35c4b5ee811 Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Wed, 18 Feb 2015 17:50:33 -0800 Subject: [PATCH] Add more options for calling removeWordFromPersonalizedDicts. Bug: 19441205 Change-Id: I41aff536a64271d2dc9489a20df33d64170756cc --- .../inputmethod/latin/common/Constants.java | 4 ++ .../latin/DictionaryFacilitator.java | 4 +- .../latin/DictionaryFacilitatorImpl.java | 10 +++- .../latin/inputlogic/InputLogic.java | 55 ++++++++++++++++++- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/common/src/com/android/inputmethod/latin/common/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java index 03abb0fdd..b491c8cfd 100644 --- a/common/src/com/android/inputmethod/latin/common/Constants.java +++ b/common/src/com/android/inputmethod/latin/common/Constants.java @@ -325,6 +325,10 @@ public final class Constants { public static final int DECODER_SCORE_SCALAR = 1000000; public static final int DECODER_MAX_SCORE = 1000000000; + public static final int EVENT_BACKSPACE = 1; + public static final int EVENT_REJECTION = 2; + public static final int EVENT_REVERT = 3; + private Constants() { // This utility class is not publicly instantiable. } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index c22dc287c..9f48501d6 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -150,7 +150,9 @@ public interface DictionaryFacilitator { @Nonnull final NgramContext ngramContext, final int timeStampInSeconds, final boolean blockPotentiallyOffensive); - void removeWordFromPersonalizedDicts(final String word); + void unlearnFromUserHistory(final String word, + @Nonnull final NgramContext ngramContext, final int timeStampInSeconds, + final int eventType); // TODO: Revise the way to fusion suggestion results. SuggestionResults getSuggestionResults(final WordComposer composer, diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java index 3d76751ce..ba70114e7 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java @@ -654,8 +654,14 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } } - public void removeWordFromPersonalizedDicts(final String word) { - removeWord(Dictionary.TYPE_USER_HISTORY, word); + @Override + public void unlearnFromUserHistory(final String word, + @Nonnull final NgramContext ngramContext, final int timeStampInSeconds, + final int eventType) { + // TODO: Decide whether or not to remove the word on EVENT_BACKSPACE. + if (eventType != Constants.EVENT_BACKSPACE) { + removeWord(Dictionary.TYPE_USER_HISTORY, word); + } } // TODO: Revise the way to fusion suggestion results. diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 9154cc35a..56be23f5b 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -1007,7 +1007,8 @@ public final class InputLogic { mWordComposer.reset(); mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion); if (!TextUtils.isEmpty(rejectedSuggestion)) { - mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion); + unlearnWord(rejectedSuggestion, inputTransaction.mSettingsValues, + Constants.EVENT_REJECTION); } StatsUtils.onBackspaceWordDelete(rejectedSuggestion.length()); } else { @@ -1060,6 +1061,8 @@ public final class InputLogic { } } + boolean hasUnlearnedWordBeingDeleted = false; + // No cancelling of commit/double space/swap: we have a regular backspace. // We should backspace one char and restart suggestion if at the end of a word. if (mConnection.hasSelection()) { @@ -1090,6 +1093,11 @@ public final class InputLogic { sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); int totalDeletedLength = 1; if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) { + // If this is an accelerated (i.e., double) deletion, then we need to + // consider unlearning here too because we may have just entered the + // previous word, and the next deletion will currupt it. + hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted( + inputTransaction.mSettingsValues, currentKeyboardScriptId); sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); totalDeletedLength++; } @@ -1112,6 +1120,11 @@ public final class InputLogic { mConnection.deleteSurroundingText(lengthToDelete, 0); int totalDeletedLength = lengthToDelete; if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) { + // If this is an accelerated (i.e., double) deletion, then we need to + // consider unlearning here too because we may have just entered the + // previous word, and the next deletion will currupt it. + hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted( + inputTransaction.mSettingsValues, currentKeyboardScriptId); final int codePointBeforeCursorToDeleteAgain = mConnection.getCodePointBeforeCursor(); if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) { @@ -1124,6 +1137,11 @@ public final class InputLogic { StatsUtils.onBackspacePressed(totalDeletedLength); } } + if (!hasUnlearnedWordBeingDeleted) { + // Consider unlearning the word being deleted (if we have not done so already). + unlearnWordBeingDeleted( + inputTransaction.mSettingsValues, currentKeyboardScriptId); + } if (inputTransaction.mSettingsValues.isSuggestionsEnabledPerUserSettings() && inputTransaction.mSettingsValues.mSpacingAndPunctuations .mCurrentLanguageHasSpaces @@ -1135,6 +1153,38 @@ public final class InputLogic { } } + boolean unlearnWordBeingDeleted( + final SettingsValues settingsValues,final int currentKeyboardScriptId) { + // If we just started backspacing to delete a previous word (but have not + // entered the composing state yet), unlearn the word. + // TODO: Consider tracking whether or not this word was typed by the user. + if (!mConnection.hasSelection() + && settingsValues.isSuggestionsEnabledPerUserSettings() + && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces + && !mConnection.isCursorFollowedByWordCharacter( + settingsValues.mSpacingAndPunctuations)) { + final TextRange range = mConnection.getWordRangeAtCursor( + settingsValues.mSpacingAndPunctuations, + currentKeyboardScriptId); + final String wordBeingDeleted = range.mWord.toString(); + if (!wordBeingDeleted.isEmpty()) { + unlearnWord(wordBeingDeleted, settingsValues, + Constants.EVENT_BACKSPACE); + return true; + } + } + return false; + } + + void unlearnWord(final String word, final SettingsValues settingsValues, final int eventType) { + final NgramContext ngramContext = mConnection.getNgramContextFromNthPreviousWord( + settingsValues.mSpacingAndPunctuations, 2); + final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds( + System.currentTimeMillis()); + mDictionaryFacilitator.unlearnFromUserHistory( + word, ngramContext, timeStampInSeconds, eventType); + } + /** * Handle a press on the language switch key (the "globe key") */ @@ -1546,7 +1596,8 @@ public final class InputLogic { } mConnection.deleteSurroundingText(deleteLength, 0); if (!TextUtils.isEmpty(committedWord)) { - mDictionaryFacilitator.removeWordFromPersonalizedDicts(committedWordString); + unlearnWord(committedWordString, inputTransaction.mSettingsValues, + Constants.EVENT_REVERT); } final String stringToCommit = originallyTypedWord + (usePhantomSpace ? "" : separatorString);