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

Commit 22e01d56 authored by Keisuke Kuroyanagi's avatar Keisuke Kuroyanagi Committed by android-build-merger
Browse files

Merge "Refresh action mode always when selection is modified." into nyc-dev

am: bd4b217a

* commit 'bd4b217a':
  Refresh action mode always when selection is modified.
parents 2a76eb06 bd4b217a
Loading
Loading
Loading
Loading
+104 −69
Original line number Diff line number Diff line
@@ -215,7 +215,7 @@ public class Editor {

    boolean mInBatchEditControllers;
    boolean mShowSoftInputOnFocus = true;
    boolean mPreserveDetachedSelection;
    private boolean mPreserveDetachedSelection;
    boolean mTemporaryDetach;

    boolean mIsBeingLongClicked;
@@ -352,7 +352,6 @@ public class Editor {

    void replace() {
        int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
        stopTextActionMode();
        Selection.setSelection((Spannable) mTextView.getText(), middle);
        showSuggestions();
    }
@@ -429,10 +428,8 @@ public class Editor {
            mSpellChecker = null;
        }

        mPreserveDetachedSelection = true;
        hideCursorAndSpanControllers();
        stopTextActionMode();
        mPreserveDetachedSelection = false;
        stopTextActionModeWithPreservingSelection();
        mTemporaryDetach = false;
    }

@@ -1104,7 +1101,6 @@ public class Editor {
                mInsertionControllerEnabled) {
            final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
                    mLastDownPositionY);
            stopTextActionMode();
            Selection.setSelection((Spannable) mTextView.getText(), offset);
            getInsertionController().show();
            mIsInsertionActionModeStartPending = true;
@@ -1208,18 +1204,15 @@ public class Editor {
            mTextView.onEndBatchEdit();

            if (mTextView.isInExtractedMode()) {
                // terminateTextSelectionMode removes selection, which we want to keep when
                // ExtractEditText goes out of focus.
                final int selStart = mTextView.getSelectionStart();
                final int selEnd = mTextView.getSelectionEnd();
                hideCursorAndSpanControllers();
                stopTextActionMode();
                Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
                stopTextActionModeWithPreservingSelection();
            } else {
                if (mTemporaryDetach) mPreserveDetachedSelection = true;
                hideCursorAndSpanControllers();
                if (mTemporaryDetach) {
                    stopTextActionModeWithPreservingSelection();
                } else {
                    stopTextActionMode();
                if (mTemporaryDetach) mPreserveDetachedSelection = false;
                }
                downgradeEasyCorrectionSpans();
            }
            // No need to create the controller
@@ -1290,10 +1283,8 @@ public class Editor {
                makeBlink();
            }
            final InputMethodManager imm = InputMethodManager.peekInstance();
            final boolean immFullScreen = (imm != null && imm.isFullscreenMode());
            if (mSelectionModifierCursorController != null && mTextView.hasSelection()
                    && !immFullScreen && mTextActionMode != null) {
                mSelectionModifierCursorController.show();
            if (mTextView.hasSelection() && !extractedTextModeWillBeStarted()) {
                startSelectionActionMode();
            }
        } else {
            if (mBlink != null) {
@@ -1304,9 +1295,7 @@ public class Editor {
            }
            // Order matters! Must be done before onParentLostFocus to rely on isShowingUp
            hideCursorAndSpanControllers();
            if (mSelectionModifierCursorController != null) {
                mSelectionModifierCursorController.hide();
            }
            stopTextActionModeWithPreservingSelection();
            if (mSuggestionsPopupWindow != null) {
                mSuggestionsPopupWindow.onParentLostFocus();
            }
@@ -1856,6 +1845,38 @@ public class Editor {
        }
    }

    void refreshTextActionMode() {
        if (extractedTextModeWillBeStarted()) {
            return;
        }
        final boolean hasSelection = mTextView.hasSelection();
        final SelectionModifierCursorController selectionController = getSelectionController();
        final InsertionPointCursorController insertionController = getInsertionController();
        if ((selectionController != null && selectionController.isCursorBeingModified())
                || (insertionController != null && insertionController.isCursorBeingModified())) {
            // ActionMode should be managed by the currently active cursor controller.
            return;
        }
        if (hasSelection) {
            if (mTextActionMode == null || selectionController == null
                    || !selectionController.isActive()) {
                // Avoid dismissing the selection if it exists.
                stopTextActionModeWithPreservingSelection();
                startSelectionActionMode();
            } else {
                mTextActionMode.invalidateContentRect();
            }
        } else {
            // Insertion action mode is started only when insertion controller is explicitly
            // activated.
            if (insertionController == null || !insertionController.isActive()) {
                stopTextActionMode();
            } else if (mTextActionMode != null) {
                mTextActionMode.invalidateContentRect();
            }
        }
    }

    /**
     * Start an Insertion action mode.
     */
@@ -1879,17 +1900,15 @@ public class Editor {

    /**
     * Starts a Selection Action Mode with the current selection and ensures the selection handles
     * are shown if there is a selection, otherwise the insertion handle is shown. This should be
     * used when the mode is started from a non-touch event.
     * are shown if there is a selection. This should be used when the mode is started from a
     * non-touch event.
     *
     * @return true if the selection mode was actually started.
     */
    boolean startSelectionActionMode() {
    private boolean startSelectionActionMode() {
        boolean selectionStarted = startSelectionActionModeInternal();
        if (selectionStarted) {
            getSelectionController().show();
        } else if (getInsertionController() != null) {
            getInsertionController().show();
        }
        return selectionStarted;
    }
@@ -1907,66 +1926,52 @@ public class Editor {
        if (extractedTextModeWillBeStarted()) {
            return false;
        }
        if (mTextActionMode != null) {
            mTextActionMode.finish();
        if (!checkField()) {
            return false;
        }
        if (!checkFieldAndSelectCurrentWord()) {
        if (!mTextView.hasSelection() && !selectCurrentWord()) {
            // No selection and cannot select a word.
            return false;
        }

        // Avoid dismissing the selection if it exists.
        mPreserveDetachedSelection = true;
        stopTextActionMode();
        mPreserveDetachedSelection = false;

        stopTextActionModeWithPreservingSelection();
        getSelectionController().enterDrag(
                SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_WORD);
        return true;
    }

    /**
     * Checks whether a selection can be performed on the current TextView and if so selects
     * the current word.
     * Checks whether a selection can be performed on the current TextView.
     *
     * @return true if there already was a selection or if the current word was selected.
     * @return true if a selection can be performed
     */
    boolean checkFieldAndSelectCurrentWord() {
    boolean checkField() {
        if (!mTextView.canSelectText() || !mTextView.requestFocus()) {
            Log.w(TextView.LOG_TAG,
                    "TextView does not support text selection. Selection cancelled.");
            return false;
        }

        if (!mTextView.hasSelection()) {
            // There may already be a selection on device rotation
            return selectCurrentWord();
        }
        return true;
    }

    private boolean startSelectionActionModeInternal() {
        if (extractedTextModeWillBeStarted()) {
            return false;
        }
        if (mTextActionMode != null) {
            // Text action mode is already started
            mTextActionMode.invalidate();
            return false;
        }

        if (!checkFieldAndSelectCurrentWord()) {
        if (!checkField() || !mTextView.hasSelection()) {
            return false;
        }

        boolean willExtract = extractedTextModeWillBeStarted();

        // Do not start the action mode when extracted text will show up full screen, which would
        // immediately hide the newly created action bar and would be visually distracting.
        if (!willExtract) {
        ActionMode.Callback actionModeCallback =
                new TextActionModeCallback(true /* hasSelection */);
            mTextActionMode = mTextView.startActionMode(
                    actionModeCallback, ActionMode.TYPE_FLOATING);
        }
        mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);

        final boolean selectionStarted = mTextActionMode != null || willExtract;
        final boolean selectionStarted = mTextActionMode != null;
        if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) {
            // Show the IME to be able to replace text, except when selecting non editable text.
            final InputMethodManager imm = InputMethodManager.peekInstance();
@@ -2107,6 +2112,12 @@ public class Editor {
        }
    }

    private void stopTextActionModeWithPreservingSelection() {
        mPreserveDetachedSelection = true;
        stopTextActionMode();
        mPreserveDetachedSelection = false;
    }

    /**
     * @return True if this view supports insertion handles.
     */
@@ -2436,16 +2447,14 @@ public class Editor {
        if (offset == -1) {
            return;
        }
        mPreserveDetachedSelection = true;
        stopTextActionMode();
        mPreserveDetachedSelection = false;
        stopTextActionModeWithPreservingSelection();
        final boolean isOnSelection = mTextView.hasSelection()
                && offset >= mTextView.getSelectionStart() && offset <= mTextView.getSelectionEnd();
        if (!isOnSelection) {
            // Right clicked position is not on the selection. Remove the selection and move the
            // cursor to the right clicked position.
            stopTextActionMode();
            Selection.setSelection((Spannable) mTextView.getText(), offset);
            stopTextActionMode();
        }

        if (shouldOfferToShowSuggestions()) {
@@ -3488,7 +3497,6 @@ public class Editor {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Editable editable = (Editable) mTextView.getText();
            SuggestionInfo suggestionInfo = mSuggestionInfos[position];

            final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan);
            final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan);
            if (spanStart < 0 || spanEnd <= spanStart) {
@@ -4391,7 +4399,7 @@ public class Editor {
                        if (distanceSquared < touchSlop * touchSlop) {
                            // Tapping on the handle toggles the insertion action mode.
                            if (mTextActionMode != null) {
                                mTextActionMode.finish();
                                stopTextActionMode();
                            } else {
                                startInsertionActionMode();
                            }
@@ -4808,6 +4816,10 @@ public class Editor {
         * preventing the activity from being recycled.
         */
        public void onDetached();

        public boolean isCursorBeingModified();

        public boolean isActive();
    }

    private class InsertionPointCursorController implements CursorController {
@@ -4851,6 +4863,16 @@ public class Editor {

            if (mHandle != null) mHandle.onDetached();
        }

        @Override
        public boolean isCursorBeingModified() {
            return mHandle != null && mHandle.isDragging();
        }

        @Override
        public boolean isActive() {
            return mHandle != null && mHandle.isShowing();
        }
    }

    class SelectionModifierCursorController implements CursorController {
@@ -5040,9 +5062,7 @@ public class Editor {

                        if (mStartOffset != offset) {
                            // Start character based drag accelerator.
                            if (mTextActionMode != null) {
                                mTextActionMode.finish();
                            }
                            stopTextActionMode();
                            enterDrag(DRAG_ACCELERATOR_MODE_CHARACTER);
                            mDiscardNextActionUp = true;
                            mHaventMovedEnoughToStartDrag = false;
@@ -5116,9 +5136,7 @@ public class Editor {
            if (mInsertionActionModeRunnable != null) {
                mTextView.removeCallbacks(mInsertionActionModeRunnable);
            }
            if (mTextActionMode != null) {
                mTextActionMode.finish();
            }
            stopTextActionMode();
            if (!selectCurrentParagraph()) {
                return false;
            }
@@ -5227,6 +5245,12 @@ public class Editor {
            mStartOffset = -1;
            mDragAcceleratorMode = DRAG_ACCELERATOR_MODE_INACTIVE;
            mSwitchedLines = false;
            final int selectionStart = mTextView.getSelectionStart();
            final int selectionEnd = mTextView.getSelectionEnd();
            if (selectionStart > selectionEnd) {
                Selection.setSelection((Spannable) mTextView.getText(),
                        selectionEnd, selectionStart);
            }
        }

        /**
@@ -5236,6 +5260,12 @@ public class Editor {
            return mStartHandle != null && mStartHandle.isDragging();
        }

        @Override
        public boolean isCursorBeingModified() {
            return isDragAcceleratorActive() || isSelectionStartDragged()
                    || (mEndHandle != null && mEndHandle.isDragging());
        }

        /**
         * @return true if the user is selecting text using the drag accelerator.
         */
@@ -5257,6 +5287,11 @@ public class Editor {
            if (mStartHandle != null) mStartHandle.onDetached();
            if (mEndHandle != null) mEndHandle.onDetached();
        }

        @Override
        public boolean isActive() {
            return mStartHandle != null && mStartHandle.isShowing();
        }
    }

    private class CorrectionHighlighter {
+18 −39
Original line number Diff line number Diff line
@@ -1511,6 +1511,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                if (result != null) {
                    if (isTextEditable()) {
                        replaceSelectionWithText(result);
                        if (mEditor != null) {
                            mEditor.refreshTextActionMode();
                        }
                    } else {
                        if (result.length() > 0) {
                            Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG)
@@ -1520,12 +1523,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                }
            } else if (mText instanceof Spannable) {
                // Reset the selection.
                stopTextActionMode();
                Selection.setSelection((Spannable) mText, getSelectionStart(), getSelectionEnd());
            }

            if (mEditor.hasSelectionController()) {
                mEditor.startSelectionActionMode();
                Selection.setSelection((Spannable) mText, getSelectionEnd());
            }
        }
    }
@@ -5393,11 +5391,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        // - onFocusChanged cannot start it when focus is given to a view with selected text (after
        //   a screen rotation) since layout is not yet initialized at that point.
        if (mEditor != null && mEditor.mCreatedWithASelection) {
            if (mEditor.extractedTextModeWillBeStarted()) {
                mEditor.checkFieldAndSelectCurrentWord();
            } else {
                mEditor.startSelectionActionMode();
            }
            mEditor.refreshTextActionMode();
            mEditor.mCreatedWithASelection = false;
        }

@@ -6594,6 +6588,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        // in the extracted view.
        mEditor.hideCursorAndSpanControllers();
        stopTextActionMode();
        if (mEditor.mSelectionModifierCursorController != null) {
            mEditor.mSelectionModifierCursorController.resetTouchOffsets();
        }
    }

    /**
@@ -8289,6 +8286,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                if (newSelEnd < 0) {
                    newSelEnd = Selection.getSelectionEnd(buf);
                }
                if (mEditor != null) {
                    mEditor.refreshTextActionMode();
                }
                onSelectionChanged(newSelStart, newSelEnd);
            }
        }
@@ -9199,10 +9199,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    }
                    if (start >= 0 && start <= end && end <= text.length()) {
                        Selection.setSelection((Spannable) text, start, end);
                        // Make sure selection mode is engaged.
                        if (mEditor != null) {
                            mEditor.startSelectionActionMode();
                        }
                        return true;
                    }
                }
@@ -9393,16 +9389,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

        switch (id) {
            case ID_SELECT_ALL:
                // This starts an action mode if triggered from another action mode. Text is
                // highlighted, so that it can be bulk edited, like selectAllOnFocus does. Returns
                // true even if text is empty.
                boolean shouldRestartActionMode =
                        mEditor != null && mEditor.mTextActionMode != null;
                stopTextActionMode();
                selectAllText();
                if (shouldRestartActionMode) {
                    mEditor.startSelectionActionMode();
                }
                return true;

            case ID_UNDO:
@@ -9428,7 +9415,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            case ID_CUT:
                setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
                deleteText_internal(min, max);
                stopTextActionMode();
                return true;

            case ID_COPY:
@@ -9684,12 +9670,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }

    boolean selectAllText() {
        // Need to hide insert point cursor controller before settings selection, otherwise insert
        // point cursor controller obtains cursor update event and update cursor with cancelling
        // selection.
        if (mEditor != null) {
            mEditor.hideInsertionPointCursorController();
        }
        final int length = mText.length();
        Selection.setSelection((Spannable) mText, 0, length);
        return length > 0;
@@ -9728,7 +9708,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    }
                }
            }
            stopTextActionMode();
            sLastCutCopyOrTextChangedTime = 0;
        }
    }
@@ -9741,7 +9720,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT);
            sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText);
            getContext().startActivity(Intent.createChooser(sharingIntent, null));
            stopTextActionMode();
            Selection.setSelection((Spannable) mText, getSelectionEnd());
        }
    }

@@ -10059,6 +10038,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                && getAccessibilitySelectionEnd() == end) {
            return;
        }
        CharSequence text = getIterableTextForAccessibility();
        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
            Selection.setSelection((Spannable) text, start, end);
        } else {
            Selection.removeSelection((Spannable) text);
        }
        // Hide all selection controllers used for adjusting selection
        // since we are doing so explicitlty by other means and these
        // controllers interact with how selection behaves.
@@ -10066,12 +10051,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            mEditor.hideCursorAndSpanControllers();
            mEditor.stopTextActionMode();
        }
        CharSequence text = getIterableTextForAccessibility();
        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
            Selection.setSelection((Spannable) text, start, end);
        } else {
            Selection.removeSelection((Spannable) text);
        }
    }

    /** @hide */