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

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

Merge changes Ia01aee85,I17bd91a1

* changes:
  Add a SpanWatcher to catch programmatic selection changes
  Initial refactoring to move updateSelection to a better place
parents 5fbbf231 baf3094e
Loading
Loading
Loading
Loading
+52 −22
Original line number Diff line number Diff line
@@ -181,7 +181,10 @@ public class Editor {
    // Set when this TextView gained focus with some text selected. Will start selection mode.
    boolean mCreatedWithASelection;

    private EasyEditSpanController mEasyEditSpanController;
    // The span controller helps monitoring the changes to which the Editor needs to react:
    // - EasyEditSpans, for which we have some UI to display on attach and on hide
    // - SelectionSpans, for which we need to call updateSelection if an IME is attached
    private SpanController mSpanController;

    WordIterator mWordIterator;
    SpellChecker mSpellChecker;
@@ -466,8 +469,8 @@ public class Editor {
    }

    private void hideSpanControllers() {
        if (mEasyEditSpanController != null) {
            mEasyEditSpanController.hide();
        if (mSpanController != null) {
            mSpanController.hide();
        }
    }

@@ -1205,6 +1208,25 @@ public class Editor {
        return false;
    }

    private void sendUpdateSelection() {
        if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0) {
            final InputMethodManager imm = InputMethodManager.peekInstance();
            if (null != imm) {
                final int selectionStart = mTextView.getSelectionStart();
                final int selectionEnd = mTextView.getSelectionEnd();
                int candStart = -1;
                int candEnd = -1;
                if (mTextView.getText() instanceof Spannable) {
                    final Spannable sp = (Spannable) mTextView.getText();
                    candStart = EditableInputConnection.getComposingSpanStart(sp);
                    candEnd = EditableInputConnection.getComposingSpanEnd(sp);
                }
                imm.updateSelection(mTextView,
                        selectionStart, selectionEnd, candStart, candEnd);
            }
        }
    }

    void onDraw(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint,
            int cursorOffsetVertical) {
        final int selectionStart = mTextView.getSelectionStart();
@@ -1223,15 +1245,9 @@ public class Editor {
                        reported = reportExtractedText();
                    }
                    if (!reported && highlight != null) {
                        int candStart = -1;
                        int candEnd = -1;
                        if (mTextView.getText() instanceof Spannable) {
                            Spannable sp = (Spannable) mTextView.getText();
                            candStart = EditableInputConnection.getComposingSpanStart(sp);
                            candEnd = EditableInputConnection.getComposingSpanEnd(sp);
                        }
                        imm.updateSelection(mTextView,
                                selectionStart, selectionEnd, candStart, candEnd);
                        // TODO: stop doing this here, and do it after each change
                        // as needed instead.
                        sendUpdateSelection();
                    }
                }

@@ -1859,17 +1875,18 @@ public class Editor {
            text.setSpan(mKeyListener, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        }

        if (mEasyEditSpanController == null) {
            mEasyEditSpanController = new EasyEditSpanController();
        if (mSpanController == null) {
            mSpanController = new SpanController();
        }
        text.setSpan(mEasyEditSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        text.setSpan(mSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
    }

    /**
     * Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
     * pop-up should be displayed.
     * Also monitors {@link SelectionSpan} to call back to the attached input method.
     */
    class EasyEditSpanController implements SpanWatcher {
    class SpanController implements SpanWatcher {

        private static final int DISPLAY_TIMEOUT_MS = 3000; // 3 secs

@@ -1877,9 +1894,18 @@ public class Editor {

        private Runnable mHidePopup;

        // This function is pure but inner classes can't have static functions
        private boolean isNonIntermediateSelectionSpan(final Spannable text,
                final Object span) {
            return (Selection.SELECTION_START == span || Selection.SELECTION_END == span)
                    && (text.getSpanFlags(span) & Spanned.SPAN_INTERMEDIATE) == 0;
        }

        @Override
        public void onSpanAdded(Spannable text, Object span, int start, int end) {
            if (span instanceof EasyEditSpan) {
            if (isNonIntermediateSelectionSpan(text, span)) {
                sendUpdateSelection();
            } else if (span instanceof EasyEditSpan) {
                if (mPopupWindow == null) {
                    mPopupWindow = new EasyEditPopupWindow();
                    mHidePopup = new Runnable() {
@@ -1903,7 +1929,7 @@ public class Editor {
                        int start = editable.getSpanStart(span);
                        int end = editable.getSpanEnd(span);
                        if (start >= 0 && end >= 0) {
                            sendNotification(EasyEditSpan.TEXT_DELETED, span);
                            sendEasySpanNotification(EasyEditSpan.TEXT_DELETED, span);
                            mTextView.deleteText_internal(start, end);
                        }
                        editable.removeSpan(span);
@@ -1934,7 +1960,9 @@ public class Editor {

        @Override
        public void onSpanRemoved(Spannable text, Object span, int start, int end) {
            if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) {
            if (isNonIntermediateSelectionSpan(text, span)) {
                sendUpdateSelection();
            } else if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) {
                hide();
            }
        }
@@ -1942,9 +1970,11 @@ public class Editor {
        @Override
        public void onSpanChanged(Spannable text, Object span, int previousStart, int previousEnd,
                int newStart, int newEnd) {
            if (mPopupWindow != null && span instanceof EasyEditSpan) {
            if (isNonIntermediateSelectionSpan(text, span)) {
                sendUpdateSelection();
            } else if (mPopupWindow != null && span instanceof EasyEditSpan) {
                EasyEditSpan easyEditSpan = (EasyEditSpan) span;
                sendNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan);
                sendEasySpanNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan);
                text.removeSpan(easyEditSpan);
            }
        }
@@ -1956,7 +1986,7 @@ public class Editor {
            }
        }

        private void sendNotification(int textChangedType, EasyEditSpan span) {
        private void sendEasySpanNotification(int textChangedType, EasyEditSpan span) {
            try {
                PendingIntent pendingIntent = span.getPendingIntent();
                if (pendingIntent != null) {