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

Commit a022c538 authored by Jean Chalard's avatar Jean Chalard Committed by Android (Google) Code Review
Browse files

Merge "If there are no suggestion span, recompute suggestions."

parents 837f46dc 0e9ee4d3
Loading
Loading
Loading
Loading
+57 −14
Original line number Diff line number Diff line
@@ -1466,8 +1466,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
                                "", mWordComposer.getTypedWord(), " ", mWordComposer);
                    }
                }
                if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
                    // If we are in the middle of a recorrection, we need to commit the recorrection
                    // first so that we can insert the character at the current cursor position.
                    resetEntireInputState(mLastSelectionStart);
                } else {
                    commitTyped(LastComposedWord.NOT_A_SEPARATOR);
                }
            }
            final int keyX, keyY;
            final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
            if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
@@ -1522,8 +1528,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
            }
            final int wordComposerSize = mWordComposer.size();
            // Since isComposingWord() is true, the size is at least 1.
            final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1);
            if (wordComposerSize <= 1) {
            final int lastChar = mWordComposer.getCodeBeforeCursor();
            if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
                // If we are in the middle of a recorrection, we need to commit the recorrection
                // first so that we can insert the batch input at the current cursor position.
                resetEntireInputState(mLastSelectionStart);
            } else if (wordComposerSize <= 1) {
                // We auto-correct the previous (typed, not gestured) string iff it's one character
                // long. The reason for this is, even in the middle of gesture typing, you'll still
                // tap one-letter words and you want them auto-corrected (typically, "i" in English
@@ -1734,8 +1744,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
        // during key repeat.
        mHandler.postUpdateShiftState();

        if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) {
        if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
            // If we are in the middle of a recorrection, we need to commit the recorrection
            // first so that we can remove the character at the current cursor position.
            resetEntireInputState(mLastSelectionStart);
            // When we exit this if-clause, mWordComposer.isComposingWord() will return false.
        }
        if (mWordComposer.isComposingWord()) {
            final int length = mWordComposer.size();
@@ -1870,7 +1883,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
            promotePhantomSpace();
        }

        if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) {
        if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
            // If we are in the middle of a recorrection, we need to commit the recorrection
            // first so that we can insert the character at the current cursor position.
            resetEntireInputState(mLastSelectionStart);
            isComposingWord = false;
        }
@@ -1935,7 +1950,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
            ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
        }
        boolean didAutoCorrect = false;
        // Handle separator
        if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
            // If we are in the middle of a recorrection, we need to commit the recorrection
            // first so that we can insert the separator at the current cursor position.
            resetEntireInputState(mLastSelectionStart);
        }
        if (mWordComposer.isComposingWord()) {
            if (mSettings.getCurrent().mCorrectionEnabled) {
                // TODO: maybe cache Strings in an <String> sparse array or something
@@ -2357,9 +2376,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
        final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
                0 /* additionalPrecedingWordsCount */);
        final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
        final String typedWord = range.mWord.toString();
        if (range.mWord instanceof SpannableString) {
            final SpannableString spannableString = (SpannableString)range.mWord;
            final String typedWord = spannableString.toString();
            int i = 0;
            for (Object object : spannableString.getSpans(0, spannableString.length(),
                    SuggestionSpan.class)) {
@@ -2374,18 +2393,42 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
                }
            }
        }
        mWordComposer.setComposingWord(range.mWord, mKeyboardSwitcher.getKeyboard());
        mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
        mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
        mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
                mLastSelectionEnd + range.mCharsAfter);
        final SuggestedWords suggestedWords;
        if (suggestions.isEmpty()) {
            suggestions.add(new SuggestedWordInfo(range.mWord.toString(), 1,
                    SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_RESUMED));
            // We come here if there weren't any suggestion spans on this word. We will try to
            // compute suggestions for it instead.
            final SuggestedWords suggestedWordsIncludingTypedWord =
                    getSuggestedWords(Suggest.SESSION_TYPING);
            if (suggestedWordsIncludingTypedWord.size() > 1) {
                // We were able to compute new suggestions for this word.
                // Remove the typed word, since we don't want to display it in this case.
                // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false.
                suggestedWords =
                        suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord();
            } else {
                // No saved suggestions, and we were unable to compute any good one either.
                // Rather than displaying an empty suggestion strip, we'll display the original
                // word alone in the middle.
                // Since there is only one word, willAutoCorrect is false.
                suggestedWords = suggestedWordsIncludingTypedWord;
            }
        showSuggestionStrip(new SuggestedWords(suggestions,
        } else {
            // We found suggestion spans in the word. We'll create the SuggestedWords out of
            // them, and make willAutoCorrect false.
            suggestedWords = new SuggestedWords(suggestions,
                    true /* typedWordValid */, false /* willAutoCorrect */,
                    false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
                false /* isPrediction */), range.mWord.toString());
                    false /* isPrediction */);
        }

        // Note that it's very important here that suggestedWords.mWillAutoCorrect is false.
        // We never want to auto-correct on a resumed suggestion. Please refer to the three
        // places above where suggestedWords is affected.
        showSuggestionStrip(suggestedWords, typedWord);
    }

    /**
+17 −0
Original line number Diff line number Diff line
@@ -195,4 +195,21 @@ public final class SuggestedWords {
            }
        }
    }

    // SuggestedWords is an immutable object, as much as possible. We must not just remove
    // words from the member ArrayList as some other parties may expect the object to never change.
    public SuggestedWords getSuggestedWordsExcludingTypedWord() {
        final ArrayList<SuggestedWordInfo> newSuggestions = CollectionUtils.newArrayList();
        for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
            final SuggestedWordInfo info = mSuggestedWordInfoList.get(i);
            if (SuggestedWordInfo.KIND_TYPED != info.mKind) {
                newSuggestions.add(info);
            }
        }
        // We should never autocorrect, so we say the typed word is valid. Also, in this case,
        // no auto-correction should take place hence willAutoCorrect = false.
        return new SuggestedWords(newSuggestions, true /* typedWordValid */,
                false /* willAutoCorrect */, mIsPunctuationSuggestions, mIsObsoleteSuggestions,
                mIsPrediction);
    }
}
+14 −2
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import java.util.Arrays;
 */
public final class WordComposer {
    private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH;
    private static final boolean DBG = LatinImeLogger.sDBG;

    public static final int CAPS_MODE_OFF = 0;
    // 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits
@@ -132,6 +133,13 @@ public final class WordComposer {
        return mPrimaryKeyCodes[index];
    }

    public int getCodeBeforeCursor() {
        if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) {
            return Constants.NOT_A_CODE;
        }
        return mPrimaryKeyCodes[mCursorPositionWithinWord - 1];
    }

    public InputPointers getInputPointers() {
        return mInputPointers;
    }
@@ -177,8 +185,12 @@ public final class WordComposer {
        mCursorPositionWithinWord = posWithinWord;
    }

    public boolean isCursorAtEndOfComposingWord() {
        return mCursorPositionWithinWord == mCodePointSize;
    public boolean isCursorFrontOrMiddleOfComposingWord() {
        if (DBG && mCursorPositionWithinWord > mCodePointSize) {
            throw new RuntimeException("Wrong cursor position : " + mCursorPositionWithinWord
                    + "in a word of size " + mCodePointSize);
        }
        return mCursorPositionWithinWord != mCodePointSize;
    }

    public void setBatchInputPointers(final InputPointers batchPointers) {
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.inputmethod.latin;

import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;

import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import java.util.ArrayList;
import java.util.Locale;

@SmallTest
public class SuggestedWordsTests extends AndroidTestCase {
    public void testGetSuggestedWordsExcludingTypedWord() {
        final String TYPED_WORD = "typed";
        final int TYPED_WORD_FREQ = 5;
        final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
        final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList();
        list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
                SuggestedWordInfo.KIND_TYPED, ""));
        for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
            list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION, ""));
        }

        final SuggestedWords words = new SuggestedWords(
                list,
                false /* typedWordValid */,
                false /* willAutoCorrect */,
                false /* isPunctuationSuggestions */,
                false /* isObsoleteSuggestions */,
                false /* isPrediction*/);
        assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size());
        assertEquals("typed", words.getWord(0));
        assertEquals(SuggestedWordInfo.KIND_TYPED, words.getInfo(0).mKind);
        assertEquals("0", words.getWord(1));
        assertEquals(SuggestedWordInfo.KIND_CORRECTION, words.getInfo(1).mKind);
        assertEquals("4", words.getWord(5));
        assertEquals(SuggestedWordInfo.KIND_CORRECTION, words.getInfo(5).mKind);

        final SuggestedWords wordsWithoutTyped = words.getSuggestedWordsExcludingTypedWord();
        assertEquals(words.size() - 1, wordsWithoutTyped.size());
        assertEquals("0", wordsWithoutTyped.getWord(0));
        assertEquals(SuggestedWordInfo.KIND_CORRECTION, wordsWithoutTyped.getInfo(0).mKind);
    }
}