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

Commit f52b121f authored by Yinglei Wang's avatar Yinglei Wang Committed by Android (Google) Code Review
Browse files

Merge "Send TYPE_VIEW_TEXT_CHANGED a11y event when SuggestionSpan is added"

parents 1c94d7da 63ab661d
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.text.Editable;
import android.text.Selection;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.method.WordIterator;
import android.text.style.SpellCheckSpan;
import android.text.style.SuggestionSpan;
@@ -416,7 +417,15 @@ public class SpellChecker implements SpellCheckerSessionListener {
                    }
                    if (spellCheckSpanStart >= 0 && spellCheckSpanEnd > spellCheckSpanStart
                            && end > start) {
                        removeErrorSuggestionSpan(editable, start, end, RemoveReason.OBSOLETE);
                        boolean visibleToAccessibility = mTextView.isVisibleToAccessibility();
                        CharSequence beforeText =
                                visibleToAccessibility ? new SpannedString(editable) : null;
                        boolean spanRemoved = removeErrorSuggestionSpan(
                                editable, start, end, RemoveReason.OBSOLETE);
                        if (visibleToAccessibility && spanRemoved) {
                            mTextView.sendAccessibilityEventTypeViewTextChanged(
                                    beforeText, start, end);
                        }
                    }
                }
                return spellCheckSpan;
@@ -437,8 +446,9 @@ public class SpellChecker implements SpellCheckerSessionListener {
        OBSOLETE,
    }

    private static void removeErrorSuggestionSpan(
    private static boolean removeErrorSuggestionSpan(
            Editable editable, int start, int end, RemoveReason reason) {
        boolean spanRemoved = false;
        SuggestionSpan[] spans = editable.getSpans(start, end, SuggestionSpan.class);
        for (SuggestionSpan span : spans) {
            if (editable.getSpanStart(span) == start
@@ -450,8 +460,10 @@ public class SpellChecker implements SpellCheckerSessionListener {
                            + editable.subSequence(start, end) + ", reason: " + reason);
                }
                editable.removeSpan(span);
                spanRemoved = true;
            }
        }
        return spanRemoved;
    }

    @Override
@@ -568,8 +580,13 @@ public class SpellChecker implements SpellCheckerSessionListener {
        }
        SuggestionSpan suggestionSpan =
                new SuggestionSpan(mTextView.getContext(), suggestions, flags);
        removeErrorSuggestionSpan(editable, start, end, RemoveReason.REPLACE);
        boolean spanRemoved = removeErrorSuggestionSpan(editable, start, end, RemoveReason.REPLACE);
        boolean sendAccessibilityEvent = !spanRemoved && mTextView.isVisibleToAccessibility();
        CharSequence beforeText = sendAccessibilityEvent ? new SpannedString(editable) : null;
        editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        if (sendAccessibilityEvent) {
            mTextView.sendAccessibilityEventTypeViewTextChanged(beforeText, start, end);
        }

        mTextView.invalidateRegion(start, end, false /* No cursor involved */);
    }
+17 −51
Original line number Diff line number Diff line
@@ -12501,6 +12501,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return TextUtils.trimToParcelableSize(mTransformed);
    }
    boolean isVisibleToAccessibility() {
        return AccessibilityManager.getInstance(mContext).isEnabled()
                && (isFocused() || (isSelected() && isShown()));
    }
    void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
            int fromIndex, int removedCount, int addedCount) {
        AccessibilityEvent event =
@@ -12512,6 +12517,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        sendAccessibilityEventUnchecked(event);
    }
    void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
            int fromIndex, int toIndex) {
        AccessibilityEvent event =
                AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
        event.setFromIndex(fromIndex);
        event.setToIndex(toIndex);
        event.setBeforeText(beforeText);
        sendAccessibilityEventUnchecked(event);
    }
    private InputMethodManager getInputMethodManager() {
        return getContext().getSystemService(InputMethodManager.class);
    }
@@ -13826,10 +13841,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            }
            TextView.this.handleTextChanged(buffer, start, before, after);
            if (AccessibilityManager.getInstance(mContext).isEnabled()
                    && (isFocused() || (isSelected() && isShown()))) {
            if (isVisibleToAccessibility()) {
                sendAccessibilityEventTypeViewTextChanged(mBeforeText, start, before, after);
                mBeforeText = TextUtils.stringOrSpannedString(mTransformed);
                mBeforeText = null;
            }
        }
@@ -13857,54 +13871,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                Log.v(LOG_TAG, "onSpanAdded s=" + s + " e=" + e + " what=" + what + ": " + buf);
            }
            TextView.this.spanChange(buf, what, -1, s, -1, e);
            // Note we don't update mBeforeText here. We look for SuggestionSpans added after the
            // text content changes.
            if (AccessibilityManager.getInstance(mContext).isEnabled()
                    && (isFocused() || (isSelected() && isShown()))
                    && (what instanceof SuggestionSpan)) {
                // When the user types a new word, and SuggestionSpans on the existing words will be
                // removed and added again. We don't need to send out events for existing
                // SuggestionSpans. Multiple spans can be placed on the range.
                if (mBeforeText instanceof SpannedString) {
                    final SpannedString beforeSpannedString = (SpannedString) mBeforeText;
                    if ((beforeSpannedString.getSpanStart(what) == s)
                            && (beforeSpannedString.getSpanEnd(what) == e)) {
                        // Exactly same span is found.
                        return;
                    }
                    // Suggestion span couldn't be found. Try to find a suggestion span that has the
                    // same contents.
                    SuggestionSpan[] suggestionSpans = beforeSpannedString.getSpans(s, e,
                            SuggestionSpan.class);
                    for (final SuggestionSpan suggestionSpan : suggestionSpans) {
                        final int start = beforeSpannedString.getSpanStart(suggestionSpan);
                        if (start != s) {
                            continue;
                        }
                        final int end = beforeSpannedString.getSpanEnd(suggestionSpan);
                        if (end != e) {
                            continue;
                        }
                        if (equalSuggestionSpan(suggestionSpan, (SuggestionSpan) what)) {
                            return;
                        }
                    }
                }
                AccessibilityEvent event =
                        AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
                event.setFromIndex(s);
                event.setToIndex(e);
                event.setBeforeText(mBeforeText);
                sendAccessibilityEventUnchecked(event);
            }
        }
        private boolean equalSuggestionSpan(SuggestionSpan span1, SuggestionSpan span2) {
            // We compare flags because flags will determine the underline color.
            return Arrays.equals(span1.getSuggestions(), span2.getSuggestions())
                    && Objects.equals(span1.getLocaleObject(), span2.getLocaleObject())
                    && span1.getLocale().equals(span2.getLocale())
                    && (span1.getFlags() == span2.getFlags());
        }
        public void onSpanRemoved(Spannable buf, Object what, int s, int e) {