Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a05a0f20 authored by Jean Chalard's avatar Jean Chalard
Browse files

Allow Latin IME to cancel smiley-auto-correct consistenly

This change makes Latin IME behave consistently with regards
to other auto-correction cancellations in cases of auto-correction
cancellation after smiley-triggered auto-correction. That is,
pressing the smiley key when the keyboard signals it's about to
auto-correct will get the auto-correction there plus a smiley,
and pressing backspace will cancel the auto-correction, and
pressing backspace again will delete the smiley.

Bug: 7067593
Change-Id: Ia7eef70a5d06b8b9afa1f1fbb0ed1dbc21a3059f
parent 6c70b920
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -38,12 +38,12 @@ public class LastComposedWord {
    // an auto-correction.
    public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3;

    public static final int NOT_A_SEPARATOR = -1;
    public static final String NOT_A_SEPARATOR = "";

    public final int[] mPrimaryKeyCodes;
    public final String mTypedWord;
    public final String mCommittedWord;
    public final int mSeparatorCode;
    public final String mSeparatorString;
    public final CharSequence mPrevWord;
    public final InputPointers mInputPointers = new InputPointers(BinaryDictionary.MAX_WORD_LENGTH);

@@ -56,14 +56,14 @@ public class LastComposedWord {
    // immutable. Do not fiddle with their contents after you passed them to this constructor.
    public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers,
            final String typedWord, final String committedWord,
            final int separatorCode, final CharSequence prevWord) {
            final String separatorString, final CharSequence prevWord) {
        mPrimaryKeyCodes = primaryKeyCodes;
        if (inputPointers != null) {
            mInputPointers.copy(inputPointers);
        }
        mTypedWord = typedWord;
        mCommittedWord = committedWord;
        mSeparatorCode = separatorCode;
        mSeparatorString = separatorString;
        mActive = true;
        mPrevWord = prevWord;
    }
@@ -80,7 +80,7 @@ public class LastComposedWord {
        return TextUtils.equals(mTypedWord, mCommittedWord);
    }

    public static int getSeparatorLength(final int separatorCode) {
        return NOT_A_SEPARATOR == separatorCode ? 0 : 1;
    public static int getSeparatorLength(final String separatorString) {
        return StringUtils.codePointCount(separatorString);
    }
}
+31 −29
Original line number Diff line number Diff line
@@ -1055,7 +1055,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
            mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
    }

    private void commitTyped(final int separatorCode) {
    private void commitTyped(final String separatorString) {
        if (!mWordComposer.isComposingWord()) return;
        final CharSequence typedWord = mWordComposer.getTypedWord();
        if (typedWord.length() > 0) {
@@ -1063,7 +1063,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
            final CharSequence prevWord = addToUserHistoryDictionary(typedWord);
            mLastComposedWord = mWordComposer.commitWord(
                    LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(),
                    separatorCode, prevWord);
                    separatorString, prevWord);
        }
    }

@@ -1340,7 +1340,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        if (!didAutoCorrect && primaryCode != Keyboard.CODE_SHIFT
                && primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL)
            mLastComposedWord.deactivate();
        if (Keyboard.CODE_DELETE != primaryCode) {
            mEnteredText = null;
        }
        mConnection.endBatchEdit();
        if (ProductionFlag.IS_EXPERIMENTAL) {
            ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
@@ -1352,7 +1354,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
    public void onTextInput(CharSequence rawText) {
        mConnection.beginBatchEdit();
        if (mWordComposer.isComposingWord()) {
            commitCurrentAutoCorrection(LastComposedWord.NOT_A_SEPARATOR);
            commitCurrentAutoCorrection(rawText.toString());
        } else {
            resetComposingState(true /* alsoResetLastComposedWord */);
        }
        mHandler.postUpdateSuggestionStrip();
        final CharSequence text = specificTldProcessingOnTextInput(rawText);
@@ -1365,7 +1369,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT);
        mSpaceState = SPACE_STATE_NONE;
        mEnteredText = text;
        resetComposingState(true /* alsoResetLastComposedWord */);
    }

    @Override
@@ -1451,18 +1454,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        // In many cases, we may have to put the keyboard in auto-shift state again.
        mHandler.postUpdateShiftState();

        if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
            // Cancel multi-character input: remove the text we just entered.
            // This is triggered on backspace after a key that inputs multiple characters,
            // like the smiley key or the .com key.
            final int length = mEnteredText.length();
            mConnection.deleteSurroundingText(length, 0);
            // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
            // In addition we know that spaceState is false, and that we should not be
            // reverting any autocorrect at this point. So we can safely return.
            return;
        }

        if (mWordComposer.isComposingWord()) {
            final int length = mWordComposer.size();
            if (length > 0) {
@@ -1483,6 +1474,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                revertCommit();
                return;
            }
            if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
                // Cancel multi-character input: remove the text we just entered.
                // This is triggered on backspace after a key that inputs multiple characters,
                // like the smiley key or the .com key.
                final int length = mEnteredText.length();
                mConnection.deleteSurroundingText(length, 0);
                mEnteredText = null;
                // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
                // In addition we know that spaceState is false, and that we should not be
                // reverting any autocorrect at this point. So we can safely return.
                return;
            }
            if (SPACE_STATE_DOUBLE == spaceState) {
                mHandler.cancelDoubleSpacesTimer();
                if (mConnection.revertDoubleSpace()) {
@@ -1626,10 +1629,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        // Handle separator
        if (mWordComposer.isComposingWord()) {
            if (mCurrentSettings.mCorrectionEnabled) {
                commitCurrentAutoCorrection(primaryCode);
                // TODO: maybe cache Strings in an <String> sparse array or something
                commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
                didAutoCorrect = true;
            } else {
                commitTyped(primaryCode);
                commitTyped(new String(new int[]{primaryCode}, 0, 1));
            }
        }

@@ -1834,7 +1838,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        setSuggestionStripShown(isSuggestionsStripVisible());
    }

    private void commitCurrentAutoCorrection(final int separatorCodePoint) {
    private void commitCurrentAutoCorrection(final String separatorString) {
        // Complete any pending suggestions query first
        if (mHandler.hasPendingUpdateSuggestions()) {
            updateSuggestionStrip();
@@ -1848,10 +1852,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                throw new RuntimeException("We have an auto-correction but the typed word "
                        + "is empty? Impossible! I must commit suicide.");
            }
            Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint);
            Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorString);
            mExpectingUpdateSelection = true;
            commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
                    separatorCodePoint);
                    separatorString);
            if (!typedWord.equals(autoCorrection)) {
                // This will make the correction flash for a short while as a visual clue
                // to the user that auto-correction happened.
@@ -1949,7 +1953,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     * Commits the chosen word to the text field and saves it for later retrieval.
     */
    private void commitChosenWord(final CharSequence chosenWord, final int commitType,
            final int separatorCode) {
            final String separatorString) {
        final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions();
        mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
                this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1);
@@ -1960,7 +1964,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        // LastComposedWord#didCommitTypedWord by string equality of the remembered
        // strings.
        mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(),
                separatorCode, prevWord);
                separatorString, prevWord);
    }

    private void setPunctuationSuggestions() {
@@ -2030,7 +2034,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
        final CharSequence committedWord = mLastComposedWord.mCommittedWord;
        final int cancelLength = committedWord.length();
        final int separatorLength = LastComposedWord.getSeparatorLength(
                mLastComposedWord.mSeparatorCode);
                mLastComposedWord.mSeparatorString);
        // TODO: should we check our saved separator against the actual contents of the text view?
        final int deleteLength = cancelLength + separatorLength;
        if (DEBUG) {
@@ -2051,10 +2055,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
            mUserHistoryDictionary.cancelAddingUserHistory(
                    previousWord.toString(), committedWord.toString());
        }
        mConnection.commitText(originallyTypedWord, 1);
        // Re-insert the separator
        sendKeyCodePoint(mLastComposedWord.mSeparatorCode);
        Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode,
        mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
        Utils.Stats.onSeparator(mLastComposedWord.mSeparatorString,
                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
        if (ProductionFlag.IS_EXPERIMENTAL) {
            ResearchLogger.latinIME_revertCommit(originallyTypedWord);
+22 −7
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;

import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -404,23 +403,39 @@ public class Utils {
    }

    public static class Stats {
        static final int NOT_A_SEPARATOR_CODE_POINT = -1;

        public static void onNonSeparator(final char code, final int x,
                final int y) {
            RingCharBuffer.getInstance().push(code, x, y);
            LatinImeLogger.logOnInputChar();
        }

        public static void onSeparator(final int code, final int x,
                final int y) {
        public static void onSeparator(final int code, final int x, final int y) {
            // Helper method to log a single code point separator
            // TODO: cache this mapping of a code point to a string in a sparse array in StringUtils
            onSeparator(new String(new int[]{code}, 0, 1), x, y);
        }

        public static void onSeparator(final String separator, final int x, final int y) {
            final int length = separator.length();
            for (int i = 0; i < length; i = Character.offsetByCodePoints(separator, i, 1)) {
                int codePoint = Character.codePointAt(separator, i);
                // TODO: accept code points
            RingCharBuffer.getInstance().push((char)code, x, y);
                RingCharBuffer.getInstance().push((char)codePoint, x, y);
            }
            LatinImeLogger.logOnInputSeparator();
        }

        public static void onAutoCorrection(final String typedWord, final String correctedWord,
                final int separatorCode) {
                final String separatorString) {
            if (TextUtils.isEmpty(typedWord)) return;
            LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, separatorCode);
            // TODO: this fails when the separator is more than 1 code point long, but
            // the backend can't handle it yet. The only case when this happens is with
            // smileys and other multi-character keys.
            final int codePoint = TextUtils.isEmpty(separatorString) ? NOT_A_SEPARATOR_CODE_POINT
                    : separatorString.codePointAt(0);
            LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, codePoint);
        }

        public static void onAutoCorrectionCancellation() {
+2 −2
Original line number Diff line number Diff line
@@ -336,14 +336,14 @@ public class WordComposer {

    // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above.
    public LastComposedWord commitWord(final int type, final String committedWord,
            final int separatorCode, final CharSequence prevWord) {
            final String separatorString, final CharSequence prevWord) {
        // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK
        // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate
        // the last composed word to ensure this does not happen.
        final int[] primaryKeyCodes = mPrimaryKeyCodes;
        mPrimaryKeyCodes = new int[N];
        final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes,
                mInputPointers, mTypedWord.toString(), committedWord, separatorCode,
                mInputPointers, mTypedWord.toString(), committedWord, separatorString,
                prevWord);
        mInputPointers.reset();
        if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD