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

Commit 9327e677 authored by Keisuke Kuroyanagi's avatar Keisuke Kuroyanagi Committed by android-build-merger
Browse files

Merge "Stop automatically creating selection action mode." into nyc-dev am: 126fdf10

am: 6229859e

* commit '6229859e':
  Stop automatically creating selection action mode.
parents ee7ce3cc 6229859e
Loading
Loading
Loading
Loading
+26 −28
Original line number Diff line number Diff line
@@ -217,6 +217,7 @@ public class Editor {
    boolean mInBatchEditControllers;
    boolean mShowSoftInputOnFocus = true;
    private boolean mPreserveSelection;
    private boolean mRestartActionModeOnNextRefresh;
    boolean mTemporaryDetach;

    boolean mIsBeingLongClicked;
@@ -381,9 +382,8 @@ public class Editor {
        updateSpellCheckSpans(0, mTextView.getText().length(),
                true /* create the spell checker if needed */);

        if (mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
            // We had an active selection from before, start the selection mode.
            startSelectionActionMode();
        if (mTextView.hasSelection()) {
            refreshTextActionMode();
        }

        getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
@@ -1284,7 +1284,7 @@ public class Editor {
            }
            final InputMethodManager imm = InputMethodManager.peekInstance();
            if (mTextView.hasSelection() && !extractedTextModeWillBeStarted()) {
                startSelectionActionMode();
                refreshTextActionMode();
            }
        } else {
            if (mBlink != null) {
@@ -1847,6 +1847,7 @@ public class Editor {

    void refreshTextActionMode() {
        if (extractedTextModeWillBeStarted()) {
            mRestartActionModeOnNextRefresh = false;
            return;
        }
        final boolean hasSelection = mTextView.hasSelection();
@@ -1855,12 +1856,19 @@ public class Editor {
        if ((selectionController != null && selectionController.isCursorBeingModified())
                || (insertionController != null && insertionController.isCursorBeingModified())) {
            // ActionMode should be managed by the currently active cursor controller.
            mRestartActionModeOnNextRefresh = false;
            return;
        }
        if (hasSelection) {
            if (mTextActionMode == null || selectionController == null
                    || !selectionController.isActive()) {
                // Avoid dismissing the selection if it exists.
            hideInsertionPointCursorController();
            if (mTextActionMode == null) {
                if (mRestartActionModeOnNextRefresh || mTextView.isInExtractedMode()) {
                    // To avoid distraction, newly start action mode only when selection action
                    // mode is being restarted or in full screen extracted mode.
                    startSelectionActionMode();
                }
            } else if (selectionController == null || !selectionController.isActive()) {
                // Insertion action mode is active. Avoid dismissing the selection.
                stopTextActionModeWithPreservingSelection();
                startSelectionActionMode();
            } else {
@@ -1875,6 +1883,7 @@ public class Editor {
                mTextActionMode.invalidateContentRect();
            }
        }
        mRestartActionModeOnNextRefresh = false;
    }

    /**
@@ -1905,11 +1914,12 @@ public class Editor {
     *
     * @return true if the selection mode was actually started.
     */
    private boolean startSelectionActionMode() {
    boolean startSelectionActionMode() {
        boolean selectionStarted = startSelectionActionModeInternal();
        if (selectionStarted) {
            getSelectionController().show();
        }
        mRestartActionModeOnNextRefresh = false;
        return selectionStarted;
    }

@@ -2113,6 +2123,9 @@ public class Editor {
    }

    private void stopTextActionModeWithPreservingSelection() {
        if (mTextActionMode != null) {
            mRestartActionModeOnNextRefresh = true;
        }
        mPreserveSelection = true;
        stopTextActionMode();
        mPreserveSelection = false;
@@ -3707,6 +3720,8 @@ public class Editor {

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // Clear mTextActionMode not to recursively destroy action mode by clearing selection.
            mTextActionMode = null;
            Callback customCallback = getCustomCallback();
            if (customCallback != null) {
                customCallback.onDestroyActionMode(mode);
@@ -3725,8 +3740,6 @@ public class Editor {
            if (mSelectionModifierCursorController != null) {
                mSelectionModifierCursorController.hide();
            }

            mTextActionMode = null;
        }

        @Override
@@ -5129,27 +5142,12 @@ public class Editor {
                    // No longer dragging to select text, let the parent intercept events.
                    mTextView.getParent().requestDisallowInterceptTouchEvent(false);

                    int startOffset = mTextView.getSelectionStart();
                    int endOffset = mTextView.getSelectionEnd();

                    // Since we don't let drag handles pass once they're visible, we need to
                    // make sure the start / end locations are correct because the user *can*
                    // switch directions during the initial drag.
                    if (endOffset < startOffset) {
                        int tmp = endOffset;
                        endOffset = startOffset;
                        startOffset = tmp;
                    // No longer the first dragging motion, reset.
                    resetDragAcceleratorState();

                        // Also update the selection with the right offsets in this case.
                        Selection.setSelection((Spannable) mTextView.getText(),
                                startOffset, endOffset);
                    }
                    if (startOffset != endOffset) {
                    if (mTextView.hasSelection()) {
                        startSelectionActionMode();
                    }

                    // No longer the first dragging motion, reset.
                    resetDragAcceleratorState();
                    break;
            }
        }
+4 −0
Original line number Diff line number Diff line
@@ -9212,6 +9212,10 @@ 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;
                    }
                }
+66 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ import com.android.frameworks.coretests.R;
import android.support.test.espresso.action.EspressoKey;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.Selection;
import android.text.Spannable;
import android.view.KeyEvent;

import static org.hamcrest.Matchers.anyOf;
@@ -538,4 +540,68 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
        onView(withId(R.id.textview)).check(hasSelection("hijk"));
    }

    @SmallTest
    public void testSetSelectionAndActionMode() throws Exception {
        final String text = "abc def";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(replaceText(text));

        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
        assertFloatingToolbarIsNotDisplayed();
        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
        getInstrumentation().waitForIdleSync();
        sleepForFloatingToolbarPopup();
        // Don't automatically start action mode.
        assertFloatingToolbarIsNotDisplayed();
        // Make sure that "Select All" is included in the selection action mode when the entire text
        // is not selected.
        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('e')));
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        // Changing the selection range by API should not interrupt the selection action mode.
        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
        getInstrumentation().waitForIdleSync();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarContainsItem(
                getActivity().getString(com.android.internal.R.string.selectAll));
        // Make sure that "Select All" is no longer included when the entire text is selected by
        // API.
        textView.post(
                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
        getInstrumentation().waitForIdleSync();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarDoesNotContainItem(
                getActivity().getString(com.android.internal.R.string.selectAll));
        // Make sure that shrinking the selection range to cursor (an empty range) by API
        // terminates selection action mode and does not trigger the insertion action mode.
        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0));
        getInstrumentation().waitForIdleSync();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsNotDisplayed();
        // Make sure that user click can trigger the insertion action mode.
        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        // Make sure that an existing insertion action mode keeps alive after the insertion point is
        // moved by API.
        textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0));
        getInstrumentation().waitForIdleSync();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarDoesNotContainItem(
                getActivity().getString(com.android.internal.R.string.copy));
        // Make sure that selection action mode is started after selection is created by API when
        // insertion action mode is active.
        textView.post(
                () -> Selection.setSelection((Spannable) textView.getText(), 1, text.length()));
        getInstrumentation().waitForIdleSync();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarContainsItem(
                getActivity().getString(com.android.internal.R.string.copy));
    }
}