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

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

Merge "TextView tests: open context menu on right click."

parents d056081e a0b3c068
Loading
Loading
Loading
Loading
+60 −22
Original line number Diff line number Diff line
@@ -26,8 +26,11 @@ 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.hasInsertionPointerAtIndex;
import static android.widget.espresso.TextViewAssertions.hasSelection;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
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;
@@ -37,8 +40,11 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;

import com.android.frameworks.coretests.R;

import android.support.test.espresso.Espresso;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.MotionEvent;
import android.widget.espresso.ContextMenuUtils;

/**
 * Tests mouse interaction of the TextView widget from an Activity
@@ -49,10 +55,13 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<
        super(TextViewActivity.class);
    }

    @SmallTest
    public void testSelectTextByDrag() throws Exception {
    @Override
    public void setUp() {
        getActivity();
    }

    @SmallTest
    public void testSelectTextByDrag() throws Exception {
        final String helloWorld = "Hello world!";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -77,8 +86,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final String helloWorld = "Hello world!";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -89,9 +96,56 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<
    }

    @SmallTest
    public void testSelectTextByLongClick() throws Exception {
        getActivity();
    public void testContextMenu() throws Exception {
        final String text = "abc def ghi.";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));

        ContextMenuUtils.assertContextMenuIsNotDisplayed();

        onView(withId(R.id.textview)).perform(
                mouseClickOnTextAtIndex(text.indexOf("d"), MotionEvent.BUTTON_SECONDARY));

        ContextMenuUtils.assertContextMenuContainsItemDisabled(
                getActivity().getString(com.android.internal.R.string.copy));
        ContextMenuUtils.assertContextMenuContainsItemEnabled(
                getActivity().getString(com.android.internal.R.string.undo));

        // Hide context menu.
        pressBack();
        ContextMenuUtils.assertContextMenuIsNotDisplayed();

        onView(withId(R.id.textview)).perform(
                mouseDragOnText(text.indexOf("c"), text.indexOf("h")));
        onView(withId(R.id.textview)).perform(
                mouseClickOnTextAtIndex(text.indexOf("d"), MotionEvent.BUTTON_SECONDARY));

        ContextMenuUtils.assertContextMenuContainsItemEnabled(
                getActivity().getString(com.android.internal.R.string.copy));
        ContextMenuUtils.assertContextMenuContainsItemEnabled(
                getActivity().getString(com.android.internal.R.string.undo));

        // Hide context menu.
        pressBack();

        onView(withId(R.id.textview)).check(hasSelection("c def g"));

        onView(withId(R.id.textview)).perform(
                mouseClickOnTextAtIndex(text.indexOf("i"), MotionEvent.BUTTON_SECONDARY));
        ContextMenuUtils.assertContextMenuContainsItemDisabled(
                getActivity().getString(com.android.internal.R.string.copy));
        ContextMenuUtils.assertContextMenuContainsItemEnabled(
                getActivity().getString(com.android.internal.R.string.undo));

        // Hide context menu.
        pressBack();

        onView(withId(R.id.textview)).check(hasSelection(""));
        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("i")));
    }

    @SmallTest
    public void testSelectTextByLongClick() throws Exception {
        final String helloWorld = "Hello world!";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -117,8 +171,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final String helloWorld = "Hello world!";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -144,8 +196,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final String text = "abcd efg hijk lmn";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -157,8 +207,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final String text = "abcd efg hijk lmn";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -170,8 +218,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final String text = "abcd efg hijk lmn";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -183,8 +229,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final String text = "abcd efg hijk lmn";
        onView(withId(R.id.textview)).perform(click());
        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -196,8 +240,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final StringBuilder builder = new StringBuilder();
        builder.append("First paragraph.\n");
        builder.append("Second paragraph.");
@@ -232,8 +274,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final StringBuilder builder = new StringBuilder();
        builder.append("First paragraph.\n");
        builder.append("Second paragraph.");
@@ -263,8 +303,6 @@ public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<

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

        final StringBuilder builder = new StringBuilder();
        builder.append("First paragraph.\n");
        builder.append("Second paragraph.");
+110 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package android.widget.espresso;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;

import com.android.internal.view.menu.ListMenuItemView;

import android.support.test.espresso.NoMatchingRootException;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.matcher.ViewMatchers;
import android.widget.MenuPopupWindow.MenuDropDownListView;

/**
 * Espresso utility methods for the context menu.
 */
public final class ContextMenuUtils {
    private ContextMenuUtils() {}

    private static ViewInteraction onContextMenu() {
        // TODO: Have more reliable way to get context menu.
        return onView(ViewMatchers.isAssignableFrom(MenuDropDownListView.class))
                .inRoot(withDecorView(hasFocus()));
    }

    /**
     * Asserts that the context menu is displayed
     *
     * @throws AssertionError if the assertion fails
     */
    private static void assertContextMenuIsDisplayed() {
        onContextMenu().check(matches(isDisplayed()));
    }

    /**
     * Asserts that the context menu is not displayed
     *
     * @throws AssertionError if the assertion fails
     */
    public static void assertContextMenuIsNotDisplayed() {
        try {
            assertContextMenuIsDisplayed();
        } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
            return;
        }
        throw new AssertionError("Context menu is displayed");
    }

    /**
     * Asserts that the context menu contains the specified item and the item has specified enabled
     *  state.
     *
     * @param itemLabel label of the item.
     * @param enabled enabled state of the item.
     * @throws AssertionError if the assertion fails
     */
    private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
            boolean enabled) {
        onContextMenu().check(matches(
                hasDescendant(allOf(
                        isAssignableFrom(ListMenuItemView.class),
                        enabled ? isEnabled() : not(isEnabled()),
                        hasDescendant(withText(itemLabel))))));
    }

    /**
     * Asserts that the context menu contains the specified item and the item is enabled.
     *
     * @param itemLabel label of the item.
     * @throws AssertionError if the assertion fails
     */
    public static void assertContextMenuContainsItemEnabled(String itemLabel) {
        asssertContextMenuContainsItemWithEnabledState(itemLabel, true);
    }

    /**
     * Asserts that the context menu contains the specified item and the item is disabled.
     *
     * @param itemLabel label of the item.
     * @throws AssertionError if the assertion fails
     */
    public static void assertContextMenuContainsItemDisabled(String itemLabel) {
        asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
    }
}
+18 −4
Original line number Diff line number Diff line
@@ -24,9 +24,9 @@ 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.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

@@ -35,6 +35,8 @@ import android.view.ViewConfiguration;
 */
public final class MouseClickAction implements ViewAction {
    private final GeneralClickAction mGeneralClickAction;
    @MouseUiController.MouseButton
    private final int mButton;

    public enum CLICK implements Tapper {
        TRIPLE {
@@ -86,8 +88,20 @@ public final class MouseClickAction implements ViewAction {
    };

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

    /**
     * Constructs MouseClickAction
     *
     * @param tapper the tapper
     * @param coordinatesProvider the provider of the event coordinates
     * @param button the mouse button used to send motion events
     */
    public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
            @MouseUiController.MouseButton int button) {
        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
        mButton = button;
    }

    @Override
@@ -102,7 +116,7 @@ public final class MouseClickAction implements ViewAction {

    @Override
    public void perform(UiController uiController, View view) {
        mGeneralClickAction.perform(new MouseUiController(uiController), view);
        mGeneralClickAction.perform(new MouseUiController(uiController, mButton), view);
        long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
        if (0 < doubleTapTimeout) {
            // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
+29 −4
Original line number Diff line number Diff line
@@ -16,6 +16,12 @@

package android.widget.espresso;

import static com.android.internal.util.Preconditions.checkNotNull;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import android.annotation.IntDef;
import android.support.test.espresso.InjectEventSecurityException;
import android.support.test.espresso.UiController;
import android.view.InputDevice;
@@ -26,11 +32,28 @@ import android.view.MotionEvent;
 * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE.
 * Note that this doesn't change the tool type.
 */
public class MouseUiController implements UiController {
public final class MouseUiController implements UiController {
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({MotionEvent.BUTTON_PRIMARY, MotionEvent.BUTTON_SECONDARY, MotionEvent.BUTTON_TERTIARY})
    public @interface MouseButton {}

    private final UiController mUiController;
    @MouseButton
    private final int mButton;

    public MouseUiController(UiController uiController) {
        mUiController = uiController;
        this(uiController, MotionEvent.BUTTON_PRIMARY);
    }

    /**
     * Constructs MouseUiController.
     *
     * @param uiController the uiController to wrap
     * @param button the button to be used for generating input events.
     */
    public MouseUiController(UiController uiController, @MouseButton int button) {
        mUiController = checkNotNull(uiController);
        mButton = button;
    }

    @Override
@@ -40,9 +63,11 @@ public class MouseUiController implements UiController {

    @Override
    public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException {
        // Modify the event to mimic mouse primary button event.
        // Modify the event to mimic mouse event.
        event.setSource(InputDevice.SOURCE_MOUSE);
        event.setButtonState(MotionEvent.BUTTON_PRIMARY);
        if (event.getActionMasked() != MotionEvent.ACTION_UP) {
            event.setButtonState(mButton);
        }
        return mUiController.injectMotionEvent(event);
    }

+18 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tap;
import android.support.test.espresso.util.HumanReadables;
import android.text.Layout;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Editor;
import android.widget.TextView;
@@ -63,8 +64,24 @@ public final class TextViewActions {
     * @param index The index of the TextView's text to click on.
     */
    public static ViewAction mouseClickOnTextAtIndex(int index) {
        return mouseClickOnTextAtIndex(index, MotionEvent.BUTTON_PRIMARY);
    }

    /**
     * Returns an action that 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 click on.
     * @param button the mouse button to use.
     */
    public static ViewAction mouseClickOnTextAtIndex(int index,
            @MouseUiController.MouseButton int button) {
        return actionWithAssertions(
                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index)));
                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index), button));
    }

    /**