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

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

SelectAllOnFocus shows a higlighted text. DO NOT MERGE.

Bug 3201383

Highlighted is different from selected, only the background is modified
and selection mode is not started.

Tapping inside a highlighted text places the cursor. This is especially
useful for WebView and search bar has been modified to select all on focus.

Selection handles time out is no longer needed.

This CL is pretty involved and especially messes up with the terrible
ExtractedTextView, which causes a lot of problem with text selection
across device rotations.

The current implementation works pretty well. It has one problem: the handles
are not displayed when switching to landscape mode with a selected text.

This is still an improvement over the current GB version, where the handles
are not preserved at all across device rotation and where I can find more bugs.

Handles are now hidden when a context menu is displayed.

I can polish this more if we decide to include this in the MR1.

Change-Id: Id10bf2808ff25752efd59a1987e91d609ba478cd
parent ca36d863
Loading
Loading
Loading
Loading
+36 −58
Original line number Diff line number Diff line
@@ -297,6 +297,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    Drawable mSelectHandleRight;
    Drawable mSelectHandleCenter;

    // Set when this TextView gained focus with some text selected. Will start selection mode.
    private boolean mCreatedWithASelection = false;

    /*
     * Kick-start the font cache for the zygote process (to pay the cost of
     * initializing freetype for our default font only once).
@@ -3758,8 +3761,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        // - ExtractEditText does not call onFocus when it is displayed. Fixing this issue would
        //   allow to test for hasSelection in onFocusChanged, which would trigger a
        //   startTextSelectionMode here. TODO
        if (this instanceof ExtractEditText && selectionController != null && hasSelection()) {
        if (mCreatedWithASelection ||
           (this instanceof ExtractEditText && selectionController != null && hasSelection())) {
            startTextSelectionMode();
            mCreatedWithASelection = false;
        }

        mPreDrawState = PREDRAW_DONE;
@@ -4175,6 +4180,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                mInsertionPointCursorController.isShowing()) {
            mInsertionPointCursorController.updatePosition();
        }

        if (mSelectionModifierCursorController != null &&
                mSelectionModifierCursorController.isShowing()) {
            mSelectionModifierCursorController.updatePosition();
@@ -6580,6 +6586,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            int selStart = getSelectionStart();
            int selEnd = getSelectionEnd();

            // SelectAllOnFocus fields are highlighted and not selected. Do not start text selection
            // mode for these, unless there was a specific selection already started.
            final boolean isFocusHighlighted = mSelectAllOnFocus && selStart == 0 &&
                    selEnd == mText.length();
            mCreatedWithASelection = mFrozenWithFocus && hasSelection() && !isFocusHighlighted;

            if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
                // If a tap was used to give focus to that view, move cursor at tap position.
                // Has to be done before onTakeFocus, which can be overloaded.
@@ -6592,10 +6604,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    mMovement.onTakeFocus(this, (Spannable) mText, direction);
                }

                if (mSelectAllOnFocus) {
                    Selection.setSelection((Spannable) mText, 0, mText.length());
                }

                // The DecorView does not have focus when the 'Done' ExtractEditText button is
                // pressed. Since it is the ViewRoot's mView, it requests focus before
                // ExtractEditText clears focus, which gives focus to the ExtractEditText.
@@ -6614,6 +6622,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                     */
                    Selection.setSelection((Spannable) mText, selStart, selEnd);
                }

                if (mSelectAllOnFocus) {
                    Selection.setSelection((Spannable) mText, 0, mText.length());
                }

                mTouchFocusSelected = true;
            }

@@ -6643,7 +6656,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                // ExtractEditText goes out of focus.
                mIsInTextSelectionMode = false;
            } else {
                terminateTextSelectionMode();
                stopTextSelectionMode();
            }

            if (mSelectionModifierCursorController != null) {
@@ -6745,29 +6758,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        final int end = getSelectionEnd();

        if (start == end) {
            if (start >= prevStart && start < prevEnd) {
            boolean tapInsideSelectAllOnFocus = mSelectAllOnFocus && prevStart == 0 &&
                  prevEnd == mText.length();
            if (start >= prevStart && start < prevEnd && !tapInsideSelectAllOnFocus) {
                // Restore previous selection
                Selection.setSelection((Spannable)mText, prevStart, prevEnd);

                if (hasSelectionController() && !getSelectionController().isShowing()) {
                    // If the anchors aren't showing, revive them.
                    getSelectionController().show();
                } else {
                // Tapping inside the selection displays the cut/copy/paste context menu
                    // as long as the anchors are already showing.
                showContextMenu();
                }
                return;
            } else {
                // Tapping outside stops selection mode, if any
                stopTextSelectionMode();

                if (hasInsertionController() && mText.length() > 0) {
                boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
                if (hasInsertionController() && !selectAllGotFocus) {
                    getInsertionController().show();
                }
            }
        } else if (hasSelection() && hasSelectionController()) {
            getSelectionController().show();
        }
    }

@@ -6790,7 +6797,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                int end = Math.min(len, mPrevEnd);
                Selection.setSelection((Spannable)mText, start, end);

                if (hasSelection()) {
                boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
                if (hasSelection() && !selectAllGotFocus) {
                    startTextSelectionMode();
                }
            }
@@ -7147,7 +7155,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }

    private boolean canSelectText() {
        return textCanBeSelected() && mText.length() != 0;
        return hasSelectionController() && mText.length() != 0;
    }

    private boolean textCanBeSelected() {
@@ -7476,6 +7484,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }

        if (added) {
            hideControllers();
            menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
        }
    }
@@ -7652,30 +7661,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                return;
            }

            if (!requestFocus()) {
            if (!canSelectText() || !requestFocus()) {
                return;
            }

            selectCurrentWord();
            getSelectionController().show();
            final InputMethodManager imm = (InputMethodManager)
                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(this, 0, null);
            mIsInTextSelectionMode = true;
        }
    }

    /**
     * Same as {@link #stopTextSelectionMode()}, except that there is no cursor controller
     * fade out animation. Needed since the drawable and their alpha values are shared by all
     * TextViews. Switching from one TextView to another would fade the cursor controllers in the
     * new one otherwise.
     */
    private void terminateTextSelectionMode() {
        stopTextSelectionMode();
        if (mSelectionModifierCursorController != null) {
            SelectionModifierCursorController selectionModifierCursorController =
                (SelectionModifierCursorController) mSelectionModifierCursorController;
            selectionModifierCursorController.cancelFadeOutAnimation();
        }
    }

    private void stopTextSelectionMode() {
        if (mIsInTextSelectionMode) {
            Selection.setSelection((Spannable) mText, getSelectionEnd());
@@ -8052,14 +8050,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        // Whether selection anchors are active
        private boolean mIsShowing;

        private static final int DELAY_BEFORE_FADE_OUT = 4100;

        private final Runnable mHider = new Runnable() {
            public void run() {
                hide();
            }
        };

        SelectionModifierCursorController() {
            mStartHandle = new HandleView(this, HandleView.LEFT);
            mEndHandle = new HandleView(this, HandleView.RIGHT);
@@ -8076,29 +8066,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            mStartHandle.show();
            mEndHandle.show();
            hideInsertionPointCursorController();
            hideDelayed(DELAY_BEFORE_FADE_OUT);
        }

        public void hide() {
            mStartHandle.hide();
            mEndHandle.hide();
            mIsShowing = false;
            removeCallbacks(mHider);
        }

        private void hideDelayed(int delay) {
            removeCallbacks(mHider);
            postDelayed(mHider, delay);
        }

        public boolean isShowing() {
            return mIsShowing;
        }

        public void cancelFadeOutAnimation() {
            hide();
        }

        public void updatePosition(HandleView handle, int x, int y) {
            int selectionStart = getSelectionStart();
            int selectionEnd = getSelectionEnd();
@@ -8150,7 +8129,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

            mStartHandle.positionAtCursor(selectionStart, true);
            mEndHandle.positionAtCursor(selectionEnd, true);
            hideDelayed(DELAY_BEFORE_FADE_OUT);
        }

        public boolean onTouchEvent(MotionEvent event) {
+1 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@
                android:drawablePadding="2dip"
                android:singleLine="true"
                android:ellipsize="end"
                android:selectAllOnFocus="true"
                android:inputType="text|textAutoComplete"
                android:dropDownWidth="match_parent"
                android:dropDownHeight="match_parent"