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

Commit bbb5d6e2 authored by Gilles Debunne's avatar Gilles Debunne
Browse files

Fixed scrolling issue when moving cursor in long TextViews.

setSelection() was called twice by onTouchEvent, once to the previous
position, and then to the new position (unless the IME got displayed,
so that in that case the cursor is not moved).

The second call was actually triggering a call for a scroll of 0 since
view is already displaying the cursor. This scroll is filtered out by a
shortcut in ScrollView. The first setSelection's scroll does not have
the same issue (since the previous cursor's position is out of screen
and requires a scroll) and it then applied, effectively moving the cursor
to a new position but the scrolling to the previous position.

The fix is to call setSelection only once, after the IME has been asked
to display. The cursor is moved to the old/new position depending on the
resultCode in onReceiveResult in CommitSelectionReceiver.

Bug: http://b/issue?id=2778954
Change-Id: I0983fdf18993e63b230e093e703f95efe6e2d7a8
parent 7ade1be8
Loading
Loading
Loading
Loading
+38 −37
Original line number Diff line number Diff line
@@ -5662,6 +5662,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * to the user.  This will not move the cursor if it represents more than
     * one character (a selection range).  This will only work if the
     * TextView contains spannable text; otherwise it will do nothing.
     *
     * @return True is the cursor was actually moved, false otherwise.
     */
    public boolean moveCursorToVisibleOffset() {
        if (!(mText instanceof Spannable)) {
@@ -6566,25 +6568,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }

    class CommitSelectionReceiver extends ResultReceiver {
        int mNewStart;
        int mNewEnd;
        private final int mPrevStart, mPrevEnd;
        private final int mNewStart, mNewEnd;

        CommitSelectionReceiver() {
        public CommitSelectionReceiver(int mPrevStart, int mPrevEnd, int mNewStart, int mNewEnd) {
            super(getHandler());
            this.mPrevStart = mPrevStart;
            this.mPrevEnd = mPrevEnd;
            this.mNewStart = mNewStart;
            this.mNewEnd = mNewEnd;
        }

        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            if (resultCode != InputMethodManager.RESULT_SHOWN) {
                final int len = mText.length();
                if (mNewStart > len) {
                    mNewStart = len;
            int start = mNewStart;
            int end = mNewEnd;

            // Move the cursor to the new position, unless this tap was actually
            // use to show the IMM. Leave cursor unchanged in that case.
            if (resultCode == InputMethodManager.RESULT_SHOWN) {
                start = mPrevStart;
                end = mPrevEnd;
            }
                if (mNewEnd > len) {
                    mNewEnd = len;

            final int len = mText.length();
            if (start > len) {
                start = len;
            }
                Selection.setSelection((Spannable)mText, mNewStart, mNewEnd);
            if (end > len) {
                end = len;
            }
            Selection.setSelection((Spannable)mText, start, end);
        }
    }
    
@@ -6610,7 +6624,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            return superResult;
        }

        if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) {
        if ((mMovement != null || onCheckIsTextEditor()) &&
                mText instanceof Spannable && mLayout != null) {
            
            boolean handled = false;
            
@@ -6626,27 +6641,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    InputMethodManager imm = (InputMethodManager)
                            getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

                    // This is going to be gross...  if tapping on the text view
                    // causes the IME to be displayed, we don't want the selection
                    // to change.  But the selection has already changed, and
                    // we won't know right away whether the IME is getting
                    // displayed, so...
                    final int newSelStart = Selection.getSelectionStart(mText);
                    final int newSelEnd = Selection.getSelectionEnd(mText);

                    int newSelStart = Selection.getSelectionStart(mText);
                    int newSelEnd = Selection.getSelectionEnd(mText);
                    CommitSelectionReceiver csr = null;
                    if (newSelStart != oldSelStart || newSelEnd != oldSelEnd) {
                        csr = new CommitSelectionReceiver();
                        csr.mNewStart = newSelStart;
                        csr.mNewEnd = newSelEnd;
                    }
                    
                    if (imm.showSoftInput(this, 0, csr) && csr != null) {
                        // The IME might get shown -- revert to the old
                        // selection, and change to the new when we finally
                        // find out of it is okay.
                        Selection.setSelection((Spannable)mText, oldSelStart, oldSelEnd);
                        handled = true;
                        CommitSelectionReceiver csr = new CommitSelectionReceiver(
                                oldSelStart, oldSelEnd, newSelStart, newSelEnd);
                        handled = imm.showSoftInput(this, 0, csr);
                    }
                }
            }