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

Commit 95733e3c authored by Kohsuke Yatoh's avatar Kohsuke Yatoh Committed by Android (Google) Code Review
Browse files

Merge "Add API to differentiate grammar suggestions."

parents d9f98db1 291a0f96
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -50874,6 +50874,7 @@ package android.text.style {
    field @NonNull public static final android.os.Parcelable.Creator<android.text.style.SuggestionSpan> CREATOR;
    field public static final int FLAG_AUTO_CORRECTION = 4; // 0x4
    field public static final int FLAG_EASY_CORRECT = 1; // 0x1
    field public static final int FLAG_GRAMMAR_ERROR = 8; // 0x8
    field public static final int FLAG_MISSPELLED = 2; // 0x2
    field public static final int SUGGESTIONS_MAX_SIZE = 5; // 0x5
    field @Deprecated public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
@@ -58248,6 +58249,7 @@ package android.view.textservice {
    field @NonNull public static final android.os.Parcelable.Creator<android.view.textservice.SuggestionsInfo> CREATOR;
    field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4
    field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
    field public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 8; // 0x8
    field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
  }
+37 −5
Original line number Diff line number Diff line
@@ -70,6 +70,12 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
     */
    public static final int FLAG_AUTO_CORRECTION = 0x0004;

    /**
     * Sets this flag if the suggestions apply to a grammar error. This type of suggestion is
     * rendered differently to highlight the error.
     */
    public static final int FLAG_GRAMMAR_ERROR = 0x0008;

    /**
     * This action is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
     *
@@ -136,6 +142,9 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
    private float mAutoCorrectionUnderlineThickness;
    private int mAutoCorrectionUnderlineColor;

    private float mGrammarErrorUnderlineThickness;
    private int mGrammarErrorUnderlineColor;

    /**
     * @param context Context for the application
     * @param suggestions Suggestions for the string under the span
@@ -190,9 +199,11 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
    private void initStyle(Context context) {
        if (context == null) {
            mMisspelledUnderlineThickness = 0;
            mGrammarErrorUnderlineThickness = 0;
            mEasyCorrectUnderlineThickness = 0;
            mAutoCorrectionUnderlineThickness = 0;
            mMisspelledUnderlineColor = Color.BLACK;
            mGrammarErrorUnderlineColor = Color.BLACK;
            mEasyCorrectUnderlineColor = Color.BLACK;
            mAutoCorrectionUnderlineColor = Color.BLACK;
            return;
@@ -206,6 +217,14 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
        mMisspelledUnderlineColor = typedArray.getColor(
                com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);

        defStyleAttr = com.android.internal.R.attr.textAppearanceGrammarErrorSuggestion;
        typedArray = context.obtainStyledAttributes(
                null, com.android.internal.R.styleable.SuggestionSpan, defStyleAttr, 0);
        mGrammarErrorUnderlineThickness = typedArray.getDimension(
                com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
        mGrammarErrorUnderlineColor = typedArray.getColor(
                com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);

        defStyleAttr = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
        typedArray = context.obtainStyledAttributes(
                null, com.android.internal.R.styleable.SuggestionSpan, defStyleAttr, 0);
@@ -235,6 +254,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
        mMisspelledUnderlineThickness = src.readFloat();
        mAutoCorrectionUnderlineColor = src.readInt();
        mAutoCorrectionUnderlineThickness = src.readFloat();
        mGrammarErrorUnderlineColor = src.readInt();
        mGrammarErrorUnderlineThickness = src.readFloat();
    }

    /**
@@ -313,6 +334,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
        dest.writeFloat(mMisspelledUnderlineThickness);
        dest.writeInt(mAutoCorrectionUnderlineColor);
        dest.writeFloat(mAutoCorrectionUnderlineThickness);
        dest.writeInt(mGrammarErrorUnderlineColor);
        dest.writeFloat(mGrammarErrorUnderlineThickness);
    }

    @Override
@@ -362,14 +385,20 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
        final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
        final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
        final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0;
        final boolean grammarError = (mFlags & FLAG_GRAMMAR_ERROR) != 0;
        if (easy) {
            if (!misspelled) {
            if (!misspelled && !grammarError) {
                tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
            } else if (tp.underlineColor == 0) {
                // Spans are rendered in an arbitrary order. Since misspelled is less prioritary
                // than just easy, do not apply misspelled if an easy (or a mispelled) has been set
                if (grammarError) {
                    tp.setUnderlineText(
                            mGrammarErrorUnderlineColor, mGrammarErrorUnderlineThickness);
                } else {
                    tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
                }
            }
        } else if (autoCorrection) {
            tp.setUnderlineText(mAutoCorrectionUnderlineColor, mAutoCorrectionUnderlineThickness);
        }
@@ -384,11 +413,14 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
        final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
        final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
        final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0;
        final boolean grammarError = (mFlags & FLAG_GRAMMAR_ERROR) != 0;
        if (easy) {
            if (!misspelled) {
                return mEasyCorrectUnderlineColor;
            } else {
            if (grammarError) {
                return mGrammarErrorUnderlineColor;
            } else if (misspelled) {
                return mMisspelledUnderlineColor;
            } else {
                return mEasyCorrectUnderlineColor;
            }
        } else if (autoCorrection) {
            return mAutoCorrectionUnderlineColor;
+8 −0
Original line number Diff line number Diff line
@@ -45,6 +45,14 @@ public final class SuggestionsInfo implements Parcelable {
     * the result suggestions include highly recommended ones.
     */
    public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 0x0004;

    /**
     * Flag of the attributes of the suggestions that can be obtained by
     * {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
     * sentence contains a grammar error.
     */
    public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 0x0008;

    private final int mSuggestionsAttributes;
    private final String[] mSuggestions;
    private final boolean mSuggestionsAvailable;
+29 −14
Original line number Diff line number Diff line
@@ -186,6 +186,9 @@ public class Editor {
    private static final int MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START = 50;
    private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;

    private static final int FLAG_MISSPELLED_OR_GRAMMAR_ERROR =
            SuggestionSpan.FLAG_MISSPELLED | SuggestionSpan.FLAG_GRAMMAR_ERROR;

    @IntDef({MagnifierHandleTrigger.SELECTION_START,
            MagnifierHandleTrigger.SELECTION_END,
            MagnifierHandleTrigger.INSERTION})
@@ -1552,7 +1555,7 @@ public class Editor {
            for (int i = 0; i < suggestionSpans.length; i++) {
                int flags = suggestionSpans[i].getFlags();
                if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
                        && (flags & SuggestionSpan.FLAG_MISSPELLED) == 0) {
                        && (flags & FLAG_MISSPELLED_OR_GRAMMAR_ERROR) == 0) {
                    flags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
                    suggestionSpans[i].setFlags(flags);
                }
@@ -3064,8 +3067,9 @@ public class Editor {

            // Remove potential misspelled flags
            int suggestionSpanFlags = suggestionSpan.getFlags();
            if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
            if ((suggestionSpanFlags & FLAG_MISSPELLED_OR_GRAMMAR_ERROR) != 0) {
                suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
                suggestionSpanFlags &= ~SuggestionSpan.FLAG_GRAMMAR_ERROR;
                suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
                suggestionSpan.setFlags(suggestionSpanFlags);
            }
@@ -3601,19 +3605,29 @@ public class Editor {
                final int flag1 = span1.getFlags();
                final int flag2 = span2.getFlags();
                if (flag1 != flag2) {
                    // The order here should match what is used in updateDrawState
                    final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
                    final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
                    final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
                    final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
                    if (easy1 && !misspelled1) return -1;
                    if (easy2 && !misspelled2) return 1;
                    if (misspelled1) return -1;
                    if (misspelled2) return 1;
                    // Compare so that the order will be: easy -> misspelled -> grammarError
                    int easy = compareFlag(SuggestionSpan.FLAG_EASY_CORRECT, flag1, flag2);
                    if (easy != 0) return easy;
                    int misspelled = compareFlag(SuggestionSpan.FLAG_MISSPELLED, flag1, flag2);
                    if (misspelled != 0) return misspelled;
                    int grammarError = compareFlag(SuggestionSpan.FLAG_GRAMMAR_ERROR, flag1, flag2);
                    if (grammarError != 0) return grammarError;
                }

                return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
            }

            /*
             * Returns -1 if flags1 has flagToCompare but flags2 does not.
             * Returns 1 if flags2 has flagToCompare but flags1 does not.
             * Otherwise, returns 0.
             */
            private int compareFlag(int flagToCompare, int flags1, int flags2) {
                boolean hasFlag1 = (flags1 & flagToCompare) != 0;
                boolean hasFlag2 = (flags2 & flagToCompare) != 0;
                if (hasFlag1 == hasFlag2) return 0;
                return hasFlag1 ? -1 : 1;
            }
        }

        /**
@@ -3632,8 +3646,9 @@ public class Editor {
                mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
            }

            // The suggestions are sorted according to their types (easy correction first, then
            // misspelled) and to the length of the text that they cover (shorter first).
            // The suggestions are sorted according to their types (easy correction first,
            // misspelled second, then grammar error) and to the length of the text that they cover
            // (shorter first).
            Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
            mSpansLengths.clear();

@@ -3661,7 +3676,7 @@ public class Editor {
                final int spanEnd = spannable.getSpanEnd(suggestionSpan);

                if (misspelledSpanInfo != null
                        && (suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
                        && (suggestionSpan.getFlags() & FLAG_MISSPELLED_OR_GRAMMAR_ERROR) != 0) {
                    misspelledSpanInfo.mSuggestionSpan = suggestionSpan;
                    misspelledSpanInfo.mSpanStart = spanStart;
                    misspelledSpanInfo.mSpanEnd = spanEnd;
+13 −3
Original line number Diff line number Diff line
@@ -338,11 +338,13 @@ public class SpellChecker implements SpellCheckerSessionListener {
                        ((attributes & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) > 0);
                final boolean looksLikeTypo =
                        ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
                final boolean looksLikeGrammarError =
                        ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR) > 0);

                final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[k];
                //TODO: we need to change that rule for results from a sentence-level spell
                // checker that will probably be in dictionary.
                if (!isInDictionary && looksLikeTypo) {
                if (!isInDictionary && (looksLikeTypo || looksLikeGrammarError)) {
                    createMisspelledSuggestionSpan(
                            editable, suggestionsInfo, spellCheckSpan, offset, length);
                } else {
@@ -482,8 +484,16 @@ public class SpellChecker implements SpellCheckerSessionListener {
            suggestions = ArrayUtils.emptyArray(String.class);
        }

        SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
                SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
        final int suggestionsAttrs = suggestionsInfo.getSuggestionsAttributes();
        int flags = SuggestionSpan.FLAG_EASY_CORRECT;
        if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) != 0) {
            flags |= SuggestionSpan.FLAG_MISSPELLED;
        }
        if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR) != 0) {
            flags |= SuggestionSpan.FLAG_GRAMMAR_ERROR;
        }
        SuggestionSpan suggestionSpan =
                new SuggestionSpan(mTextView.getContext(), suggestions, flags);
        // TODO: Remove mIsSentenceSpellCheckSupported by extracting an interface
        // to share the logic of word level spell checker and sentence level spell checker
        if (mIsSentenceSpellCheckSupported) {
Loading