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

Commit 2b69da51 authored by Keisuke Kuroyanagi's avatar Keisuke Kuroyanagi Committed by Android (Google) Code Review
Browse files

Merge "TextView tests: Add mouse triple click tests."

parents 4368d05a 46faad60
Loading
Loading
Loading
Loading
+101 −0
Original line number Diff line number Diff line
@@ -24,9 +24,12 @@ import static android.widget.espresso.TextViewActions.mouseLongClickOnTextAtInde
import static android.widget.espresso.TextViewActions.mouseDoubleClickAndDragOnText;
import static android.widget.espresso.TextViewActions.mouseDragOnText;
import static android.widget.espresso.TextViewActions.mouseLongClickAndDragOnText;
import static android.widget.espresso.TextViewActions.mouseTripleClickAndDragOnText;
import static android.widget.espresso.TextViewActions.mouseTripleClickOnTextAtIndex;
import static android.widget.espresso.TextViewAssertions.hasSelection;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -190,4 +193,102 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<
                mouseLongClickAndDragOnText(text.indexOf("j"), text.indexOf("f")));
        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
    }

    @SmallTest
    public void testSelectTextByTripleClick() throws Exception {
        getActivity();

        final StringBuilder builder = new StringBuilder();
        builder.append("First paragraph.\n");
        builder.append("Second paragraph.");
        for (int i = 0; i < 10; i++) {
            builder.append(" This paragraph is very long.");
        }
        builder.append('\n');
        builder.append("Third paragraph.");
        final String text = builder.toString();

        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(replaceText(text));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickOnTextAtIndex(text.indexOf("rst")));
        onView(withId(R.id.textview)).check(hasSelection("First paragraph.\n"));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickOnTextAtIndex(text.indexOf("cond")));
        onView(withId(R.id.textview)).check(hasSelection(
                text.substring(text.indexOf("Second"), text.indexOf("Third"))));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickOnTextAtIndex(text.indexOf("ird")));
        onView(withId(R.id.textview)).check(hasSelection("Third paragraph."));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickOnTextAtIndex(text.indexOf("very long")));
        onView(withId(R.id.textview)).check(hasSelection(
                text.substring(text.indexOf("Second"), text.indexOf("Third"))));
    }

    @SmallTest
    public void testSelectTextByTripleClickAndDrag() throws Exception {
        getActivity();

        final StringBuilder builder = new StringBuilder();
        builder.append("First paragraph.\n");
        builder.append("Second paragraph.");
        for (int i = 0; i < 10; i++) {
            builder.append(" This paragraph is very long.");
        }
        builder.append('\n');
        builder.append("Third paragraph.");
        final String text = builder.toString();

        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(replaceText(text));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickAndDragOnText(text.indexOf("irst"), text.indexOf("st")));
        onView(withId(R.id.textview)).check(hasSelection("First paragraph.\n"));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickAndDragOnText(text.indexOf("cond"), text.indexOf("Third") - 2));
        onView(withId(R.id.textview)).check(hasSelection(
                text.substring(text.indexOf("Second"), text.indexOf("Third"))));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickAndDragOnText(text.indexOf("First"), text.indexOf("ird")));
        onView(withId(R.id.textview)).check(hasSelection(text));
    }

    @SmallTest
    public void testSelectTextByTripleClickAndDrag_reverse() throws Exception {
        getActivity();

        final StringBuilder builder = new StringBuilder();
        builder.append("First paragraph.\n");
        builder.append("Second paragraph.");
        for (int i = 0; i < 10; i++) {
            builder.append(" This paragraph is very long.");
        }
        builder.append('\n');
        builder.append("Third paragraph.");
        final String text = builder.toString();

        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(replaceText(text));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickAndDragOnText(text.indexOf("st"), text.indexOf("irst")));
        onView(withId(R.id.textview)).check(hasSelection("First paragraph.\n"));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickAndDragOnText(text.indexOf("Third") - 2, text.indexOf("cond")));
        onView(withId(R.id.textview)).check(hasSelection(
                text.substring(text.indexOf("Second"), text.indexOf("Third"))));

        onView(withId(R.id.textview)).perform(
                mouseTripleClickAndDragOnText(text.indexOf("ird"), text.indexOf("First")));
        onView(withId(R.id.textview)).check(hasSelection(text));
    }
}
+53 −0
Original line number Diff line number Diff line
@@ -156,6 +156,59 @@ public final class DragAction implements ViewAction {
            }
        },

        /**
         * Starts a drag with a mouse triple click.
         */
        MOUSE_TRIPLE_CLICK {
            private DownMotionPerformer downMotion = new DownMotionPerformer() {
                @Override
                @Nullable
                public MotionEvent perform(
                        UiController uiController, float[] coordinates, float[] precision) {
                    MotionEvent downEvent = MotionEvents.sendDown(
                            uiController, coordinates, precision)
                            .down;
                    for (int i = 0; i < 2; ++i) {
                        try {
                            if (!MotionEvents.sendUp(uiController, downEvent)) {
                                String logMessage = "Injection of up event as part of the triple "
                                        + "click failed. Sending cancel event.";
                                Log.d(TAG, logMessage);
                                MotionEvents.sendCancel(uiController, downEvent);
                                return null;
                            }

                            long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
                            uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
                        } finally {
                            downEvent.recycle();
                        }
                        downEvent = MotionEvents.sendDown(
                                uiController, coordinates, precision).down;
                    }
                    return downEvent;
                }
            };

            @Override
            public Status sendSwipe(
                    UiController uiController,
                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
                return sendLinearDrag(
                        uiController, downMotion, startCoordinates, endCoordinates, precision);
            }

            @Override
            public String toString() {
                return "mouse triple click and drag to select";
            }

            @Override
            public UiController wrapUiController(UiController uiController) {
                return new MouseUiController(uiController);
            }
        },

        /**
         * Starts a drag with a tap.
         */
+63 −3
Original line number Diff line number Diff line
@@ -22,9 +22,13 @@ import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.action.MotionEvents.DownResultHolder;
import android.support.test.espresso.action.PrecisionDescriber;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tapper;
import android.view.View;
import android.view.ViewConfiguration;

/**
 * ViewAction for performing an click on View by a mouse.
@@ -32,10 +36,58 @@ import android.view.View;
public final class MouseClickAction implements ViewAction {
    private final GeneralClickAction mGeneralClickAction;

    public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
            PrecisionDescriber precisionDescriber) {
    public enum CLICK implements Tapper {
        TRIPLE {
            @Override
            public Tapper.Status sendTap(UiController uiController, float[] coordinates,
                    float[] precision) {
                Tapper.Status stat = sendSingleTap(uiController, coordinates, precision);
                boolean warning = false;
                if (stat == Tapper.Status.FAILURE) {
                    return Tapper.Status.FAILURE;
                } else if (stat == Tapper.Status.WARNING) {
                    warning = true;
                }

                long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
                for (int i = 0; i < 2; i++) {
                    if (0 < doubleTapMinimumTimeout) {
                        uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
                    }
                    stat = sendSingleTap(uiController, coordinates, precision);
                    if (stat == Tapper.Status.FAILURE) {
                        return Tapper.Status.FAILURE;
                    } else if (stat == Tapper.Status.WARNING) {
                        warning = true;
                    }
                }

                if (warning) {
                    return Tapper.Status.WARNING;
                } else {
                    return Tapper.Status.SUCCESS;
                }
            }
        };

        private static Tapper.Status sendSingleTap(UiController uiController,
                float[] coordinates, float[] precision) {
            DownResultHolder res = MotionEvents.sendDown(uiController, coordinates, precision);
            try {
                if (!MotionEvents.sendUp(uiController, res.down)) {
                    MotionEvents.sendCancel(uiController, res.down);
                    return Tapper.Status.FAILURE;
                }
            } finally {
                res.down.recycle();
            }
            return res.longPress ? Tapper.Status.WARNING : Tapper.Status.SUCCESS;
        }
    };

    public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider) {
        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
                precisionDescriber);
                Press.PINPOINT);
    }

    @Override
@@ -51,5 +103,13 @@ public final class MouseClickAction implements ViewAction {
    @Override
    public void perform(UiController uiController, View view) {
        mGeneralClickAction.perform(new MouseUiController(uiController), view);
        long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
        if (0 < doubleTapTimeout) {
            // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
            // detected as a triple click. e.g. 2 double clicks are detected as a triple click and
            // a single click because espresso isn't aware of triple click detection logic, which
            // is TextView specific gesture.
            uiController.loopMainThreadForAtLeast(doubleTapTimeout);
        }
    }
}
+40 −3
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ public final class TextViewActions {
     */
    public static ViewAction mouseClickOnTextAtIndex(int index) {
        return actionWithAssertions(
                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index), Press.PINPOINT));
                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index)));
    }

    /**
@@ -94,7 +94,7 @@ public final class TextViewActions {
     */
    public static ViewAction mouseDoubleClickOnTextAtIndex(int index) {
        return actionWithAssertions(
                new MouseClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.PINPOINT));
                new MouseClickAction(Tap.DOUBLE, new TextCoordinates(index)));
    }

    /**
@@ -124,7 +124,22 @@ public final class TextViewActions {
     */
    public static ViewAction mouseLongClickOnTextAtIndex(int index) {
        return actionWithAssertions(
                new MouseClickAction(Tap.LONG, new TextCoordinates(index), Press.PINPOINT));
                new MouseClickAction(Tap.LONG, new TextCoordinates(index)));
    }

    /**
     * Returns an action that triple-clicks by mouse on text at an index on the TextView.<br>
     * <br>
     * View constraints:
     * <ul>
     * <li>must be a TextView displayed on screen
     * <ul>
     *
     * @param index The index of the TextView's text to triple-click on.
     */
    public static ViewAction mouseTripleClickOnTextAtIndex(int index) {
        return actionWithAssertions(
                new MouseClickAction(MouseClickAction.CLICK.TRIPLE, new TextCoordinates(index)));
    }

    /**
@@ -237,6 +252,28 @@ public final class TextViewActions {
                        TextView.class));
    }

    /**
    * Returns an action that triple click then drags by mouse on text from startIndex to endIndex
    * on the TextView.<br>
    * <br>
    * View constraints:
    * <ul>
    * <li>must be a TextView displayed on screen
    * <ul>
    *
    * @param startIndex The index of the TextView's text to start a drag from
    * @param endIndex The index of the TextView's text to end the drag at
    */
   public static ViewAction mouseTripleClickAndDragOnText(int startIndex, int endIndex) {
       return actionWithAssertions(
               new DragAction(
                       DragAction.Drag.MOUSE_TRIPLE_CLICK,
                       new TextCoordinates(startIndex),
                       new TextCoordinates(endIndex),
                       Press.PINPOINT,
                       TextView.class));
   }

    public enum Handle {
        SELECTION_START,
        SELECTION_END,