Loading core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java +101 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); } } core/tests/coretests/src/android/widget/espresso/DragAction.java +53 −0 Original line number Diff line number Diff line Loading @@ -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. */ Loading core/tests/coretests/src/android/widget/espresso/MouseClickAction.java +63 −3 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 Loading @@ -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); } } } core/tests/coretests/src/android/widget/espresso/TextViewActions.java +40 −3 Original line number Diff line number Diff line Loading @@ -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))); } /** Loading Loading @@ -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))); } /** Loading Loading @@ -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))); } /** Loading Loading @@ -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, Loading Loading
core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java +101 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); } }
core/tests/coretests/src/android/widget/espresso/DragAction.java +53 −0 Original line number Diff line number Diff line Loading @@ -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. */ Loading
core/tests/coretests/src/android/widget/espresso/MouseClickAction.java +63 −3 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 Loading @@ -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); } } }
core/tests/coretests/src/android/widget/espresso/TextViewActions.java +40 −3 Original line number Diff line number Diff line Loading @@ -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))); } /** Loading Loading @@ -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))); } /** Loading Loading @@ -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))); } /** Loading Loading @@ -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, Loading