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

Commit d7d47941 authored by Gilles Debunne's avatar Gilles Debunne Committed by Android Git Automerger
Browse files

am 50662f5f: Merge "TextView cursor and selection improvements." into gingerbread

Merge commit '50662f5f' into gingerbread-plus-aosp

* commit '50662f5f':
  TextView cursor and selection improvements.
parents d5423321 50662f5f
Loading
Loading
Loading
Loading
+37 −28
Original line number Diff line number Diff line
@@ -6554,12 +6554,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            int selEnd = getSelectionEnd();

            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.
                if (mLastTouchOffset >= 0) {
                    // Can happen when a TextView is displayed after its content has been deleted.
                    mLastTouchOffset = Math.min(mLastTouchOffset, mText.length());
                    Selection.setSelection((Spannable) mText, mLastTouchOffset);
                }
                moveCursorToLastTapPosition();

                if (mMovement != null) {
                    mMovement.onTakeFocus(this, (Spannable) mText, direction);
@@ -6618,8 +6615,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            } else {
                terminateTextSelectionMode();
            }

            mLastTouchOffset = -1;
        }

        startStopMarquee(focused);
@@ -6631,6 +6626,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }

    private void moveCursorToLastTapPosition() {
        if (mSelectionModifierCursorController != null) {
            int mTapToFocusPosition = ((SelectionModifierCursorController)
                    mSelectionModifierCursorController).getMinTouchOffset();
            if (mTapToFocusPosition >= 0) {
                // Safety check, should not be possible.
                if (mTapToFocusPosition > mText.length()) {
                    Log.e(LOG_TAG, "Invalid tap focus position (" + mTapToFocusPosition + " vs "
                            + mText.length() + ")");
                    mTapToFocusPosition = mText.length();
                }
                Selection.setSelection((Spannable) mText, mTapToFocusPosition);
            }
        }
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
@@ -6722,7 +6733,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                // Tapping outside stops selection mode, if any
                stopTextSelectionMode();

                if (mInsertionPointCursorController != null) {
                if (mInsertionPointCursorController != null && mText.length() > 0) {
                    mInsertionPointCursorController.show();
                }
            }
@@ -7260,7 +7271,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

        int minOffset, maxOffset;

        if (mDPadCenterIsDown || mEnterKeyIsDown) {
        if (mContextMenuTriggeredByKey) {
            minOffset = getSelectionStart();
            maxOffset = getSelectionEnd();
        } else {
@@ -7291,6 +7302,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }
    
    private String getWordForDictionary() {
        if (!mContextMenuTriggeredByKey) {
            moveCursorToLastTapPosition();
        }
        long wordLimits = getWordLimitsAt(getSelectionStart());
        if (wordLimits >= 0) {
            int start = extractRangeStartFromLong(wordLimits);
@@ -7341,6 +7355,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    protected void onCreateContextMenu(ContextMenu menu) {
        super.onCreateContextMenu(menu);
        boolean added = false;
        mContextMenuTriggeredByKey = mDPadCenterIsDown || mEnterKeyIsDown;
        // Problem with context menu on long press: the menu appears while the key in down and when
        // the key is released, the view does not receive the key_up event. This ensures that the
        // state is reset whenever the context menu action is displayed.
        // mContextMenuTriggeredByKey saved that state so that it is available in
        // onTextContextMenuItem. We cannot simply clear these flags in onTextContextMenuItem since
        // it may not be called (if the user/ discards the context menu with the back key).
        mDPadCenterIsDown = mEnterKeyIsDown = false;

        if (mIsInTextSelectionMode) {
            MenuHandler handler = new MenuHandler();
@@ -7366,21 +7388,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                added = true;
            }
        } else {
            /*
            if (!isFocused()) {
                if (isFocusable() && mInput != null) {
                    if (canCopy()) {
                        MenuHandler handler = new MenuHandler();
                        menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
                             setOnMenuItemClickListener(handler).
                             setAlphabeticShortcut('c');
                        menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
                    }
                }

                //return;
            }
             */
            MenuHandler handler = new MenuHandler();

            if (canSelectText()) {
@@ -7534,7 +7541,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

            case ID_ADD_TO_DICTIONARY:
                String word = getWordForDictionary();

                if (word != null) {
                    Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
                    i.putExtra("word", word);
@@ -8018,6 +8024,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        SelectionModifierCursorController() {
            mStartHandle = new HandleView(this, HandleView.LEFT);
            mEndHandle = new HandleView(this, HandleView.RIGHT);
            mMinTouchOffset = mMaxTouchOffset = -1;
        }

        public void show() {
@@ -8100,14 +8107,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }

        public boolean onTouchEvent(MotionEvent event) {
            if (isFocused() && isTextEditable()) {
            // This is done even when the View does not have focus, so that long presses can start
            // selection and tap can move cursor from this tap position.
            if (isTextEditable()) {
                switch (event.getActionMasked()) {
                    case MotionEvent.ACTION_DOWN:
                        final int x = (int) event.getX();
                        final int y = (int) event.getY();

                        // Remember finger down position, to be able to start selection from there
                        mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y);
                        mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);

                        break;

@@ -8264,11 +8273,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    private CursorController        mInsertionPointCursorController;
    private CursorController        mSelectionModifierCursorController;
    private boolean                 mIsInTextSelectionMode = false;
    private int                     mLastTouchOffset = -1;
    // These are needed to desambiguate a long click. If the long click comes from ones of these, we
    // select from the current cursor position. Otherwise, select from long pressed position.
    private boolean                 mDPadCenterIsDown = false;
    private boolean                 mEnterKeyIsDown = false;
    private boolean                 mContextMenuTriggeredByKey = false;
    // Created once and shared by different CursorController helper methods.
    // Only one cursor controller is active at any time which prevent race conditions.
    private static Rect             sCursorControllerTempRect = new Rect();