Loading core/java/com/android/internal/widget/FloatingToolbar.java +5 −1 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ public final class FloatingToolbar { // This class is responsible for the public API of the floating toolbar. // It delegates rendering operations to the FloatingToolbarPopup. public static final String FLOATING_TOOLBAR_TAG = "floating_toolbar"; private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER = new MenuItem.OnMenuItemClickListener() { @Override Loading Loading @@ -1460,8 +1462,10 @@ public final class FloatingToolbar { } private static ViewGroup createContentContainer(Context context) { return (ViewGroup) LayoutInflater.from(context) ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context) .inflate(R.layout.floating_popup_container, null); contentContainer.setTag(FLOATING_TOOLBAR_TAG); return contentContainer; } private static PopupWindow createPopupWindow(View content) { Loading core/tests/coretests/src/android/widget/TextViewActivityTest.java +80 −0 Original line number Diff line number Diff line Loading @@ -18,8 +18,12 @@ package android.widget; import static android.widget.espresso.TextViewActions.clickOnTextAtIndex; import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText; import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex; import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; import static android.widget.espresso.TextViewAssertions.hasSelection; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; 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.pressKey; Loading Loading @@ -59,6 +63,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV getActivity(); final String helloWorld = "Hello world!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world"))); Loading @@ -67,11 +72,40 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV onView(withId(R.id.textview)).check(matches(withText("Hello orld!"))); } @SmallTest public void testLongPressToSelect() throws Exception { getActivity(); final String helloWorld = "Hello Kirk!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( longPressOnTextAtIndex(helloWorld.indexOf("Kirk"))); onView(withId(R.id.textview)).check(hasSelection("Kirk")); } @SmallTest public void testLongPressEmptySpace() throws Exception { getActivity(); final String helloWorld = "Hello big round sun!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); // Move cursor somewhere else onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big"))); // Long-press at end of line. onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(helloWorld.length())); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length())); } @SmallTest public void testLongPressAndDragToSelect() throws Exception { getActivity(); final String helloWorld = "Hello little handsome boy!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!"))); Loading @@ -79,15 +113,61 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV onView(withId(R.id.textview)).check(hasSelection("little handsome")); } @SmallTest public void testDoubleTapToSelect() throws Exception { getActivity(); final String helloWorld = "Hello SuetYi!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi"))); onView(withId(R.id.textview)).check(hasSelection("SuetYi")); } @SmallTest public void testDoubleTapAndDragToSelect() throws Exception { getActivity(); final String helloWorld = "Hello young beautiful girl!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!"))); onView(withId(R.id.textview)).check(hasSelection("young beautiful")); } @SmallTest public void testSelectBackwordsByTouch() throws Exception { getActivity(); final String helloWorld = "Hello king of the Jungle!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king"))); onView(withId(R.id.textview)).check(hasSelection("king of the")); } @SmallTest public void testToolbarAppearsAfterSelection() throws Exception { getActivity(); // It'll be nice to check that the toolbar is not visible (or does not exist) here // I can't currently find a way to do this. I'll get to it later. final String text = "Toolbar appears after selection."; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); onView(withId(R.id.textview)).perform( longPressOnTextAtIndex(text.indexOf("appears"))); // It takes the toolbar less than 100ms to start to animate into screen. // Ideally, we'll wait using the UiController, but I guess this works for now. Thread.sleep(100); assertFloatingToolbarIsDisplayed(getActivity()); } } core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java 0 → 100644 +49 −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.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withTagValue; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import android.app.Activity; import com.android.internal.widget.FloatingToolbar; /** * Espresso utility methods for the floating toolbar. */ public class FloatingToolbarEspressoUtils { private FloatingToolbarEspressoUtils() {} /** * Asserts that the floating toolbar is displayed on screen. * * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarIsDisplayed(Activity activity) { onView(withTagValue(is((Object) FloatingToolbar.FLOATING_TOOLBAR_TAG))) .inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))) .check(matches(isDisplayed())); } } core/tests/coretests/src/android/widget/espresso/TextViewActions.java +30 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,36 @@ public final class TextViewActions { new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER)); } /** * Returns an action that double-clicks 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 double-click on. */ public static ViewAction doubleClickOnTextAtIndex(int index) { return actionWithAssertions( new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER)); } /** * Returns an action that long presses 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 long press on. */ public static ViewAction longPressOnTextAtIndex(int index) { return actionWithAssertions( new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER)); } /** * Returns an action that long presses then drags on text from startIndex to endIndex on the * TextView.<br> Loading core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java +48 −1 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ public final class TextViewAssertions { * @param selection The expected selection. */ public static ViewAssertion hasSelection(String selection) { return new TextSelectionAssertion(is(selection)); return hasSelection(is(selection)); } /** Loading @@ -65,6 +65,53 @@ public final class TextViewAssertions { return new TextSelectionAssertion(selection); } /** * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at * a specified index.<br> * <br> * View constraints: * <ul> * <li>must be a text view displayed on screen * <ul> * * @param index The expected index. */ public static ViewAssertion hasInsertionPointerAtIndex(int index) { return hasInsertionPointerAtIndex(is(index)); } /** * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at * a specified index.<br> * <br> * View constraints: * <ul> * <li>must be a text view displayed on screen * <ul> * * @param index A matcher representing the expected index. */ public static ViewAssertion hasInsertionPointerAtIndex(final Matcher<Integer> index) { return new ViewAssertion() { @Override public void check(View view, NoMatchingViewException exception) { if (view instanceof TextView) { TextView textView = (TextView) view; int selectionStart = textView.getSelectionStart(); int selectionEnd = textView.getSelectionEnd(); try { assertThat(selectionStart, index); assertThat(selectionEnd, index); } catch (IndexOutOfBoundsException e) { throw new AssertionFailedError(e.getMessage()); } } else { throw new AssertionFailedError("TextView not found"); } } }; } /** * A {@link ViewAssertion} to check the selected text in a {@link TextView}. */ Loading Loading
core/java/com/android/internal/widget/FloatingToolbar.java +5 −1 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ public final class FloatingToolbar { // This class is responsible for the public API of the floating toolbar. // It delegates rendering operations to the FloatingToolbarPopup. public static final String FLOATING_TOOLBAR_TAG = "floating_toolbar"; private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER = new MenuItem.OnMenuItemClickListener() { @Override Loading Loading @@ -1460,8 +1462,10 @@ public final class FloatingToolbar { } private static ViewGroup createContentContainer(Context context) { return (ViewGroup) LayoutInflater.from(context) ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context) .inflate(R.layout.floating_popup_container, null); contentContainer.setTag(FLOATING_TOOLBAR_TAG); return contentContainer; } private static PopupWindow createPopupWindow(View content) { Loading
core/tests/coretests/src/android/widget/TextViewActivityTest.java +80 −0 Original line number Diff line number Diff line Loading @@ -18,8 +18,12 @@ package android.widget; import static android.widget.espresso.TextViewActions.clickOnTextAtIndex; import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText; import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex; import static android.widget.espresso.TextViewActions.longPressAndDragOnText; import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; import static android.widget.espresso.TextViewAssertions.hasSelection; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; 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.pressKey; Loading Loading @@ -59,6 +63,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV getActivity(); final String helloWorld = "Hello world!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world"))); Loading @@ -67,11 +72,40 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV onView(withId(R.id.textview)).check(matches(withText("Hello orld!"))); } @SmallTest public void testLongPressToSelect() throws Exception { getActivity(); final String helloWorld = "Hello Kirk!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( longPressOnTextAtIndex(helloWorld.indexOf("Kirk"))); onView(withId(R.id.textview)).check(hasSelection("Kirk")); } @SmallTest public void testLongPressEmptySpace() throws Exception { getActivity(); final String helloWorld = "Hello big round sun!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); // Move cursor somewhere else onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big"))); // Long-press at end of line. onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(helloWorld.length())); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length())); } @SmallTest public void testLongPressAndDragToSelect() throws Exception { getActivity(); final String helloWorld = "Hello little handsome boy!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!"))); Loading @@ -79,15 +113,61 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV onView(withId(R.id.textview)).check(hasSelection("little handsome")); } @SmallTest public void testDoubleTapToSelect() throws Exception { getActivity(); final String helloWorld = "Hello SuetYi!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi"))); onView(withId(R.id.textview)).check(hasSelection("SuetYi")); } @SmallTest public void testDoubleTapAndDragToSelect() throws Exception { getActivity(); final String helloWorld = "Hello young beautiful girl!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!"))); onView(withId(R.id.textview)).check(hasSelection("young beautiful")); } @SmallTest public void testSelectBackwordsByTouch() throws Exception { getActivity(); final String helloWorld = "Hello king of the Jungle!"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform( doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king"))); onView(withId(R.id.textview)).check(hasSelection("king of the")); } @SmallTest public void testToolbarAppearsAfterSelection() throws Exception { getActivity(); // It'll be nice to check that the toolbar is not visible (or does not exist) here // I can't currently find a way to do this. I'll get to it later. final String text = "Toolbar appears after selection."; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); onView(withId(R.id.textview)).perform( longPressOnTextAtIndex(text.indexOf("appears"))); // It takes the toolbar less than 100ms to start to animate into screen. // Ideally, we'll wait using the UiController, but I guess this works for now. Thread.sleep(100); assertFloatingToolbarIsDisplayed(getActivity()); } }
core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java 0 → 100644 +49 −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.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withTagValue; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import android.app.Activity; import com.android.internal.widget.FloatingToolbar; /** * Espresso utility methods for the floating toolbar. */ public class FloatingToolbarEspressoUtils { private FloatingToolbarEspressoUtils() {} /** * Asserts that the floating toolbar is displayed on screen. * * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarIsDisplayed(Activity activity) { onView(withTagValue(is((Object) FloatingToolbar.FLOATING_TOOLBAR_TAG))) .inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))) .check(matches(isDisplayed())); } }
core/tests/coretests/src/android/widget/espresso/TextViewActions.java +30 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,36 @@ public final class TextViewActions { new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER)); } /** * Returns an action that double-clicks 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 double-click on. */ public static ViewAction doubleClickOnTextAtIndex(int index) { return actionWithAssertions( new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER)); } /** * Returns an action that long presses 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 long press on. */ public static ViewAction longPressOnTextAtIndex(int index) { return actionWithAssertions( new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER)); } /** * Returns an action that long presses then drags on text from startIndex to endIndex on the * TextView.<br> Loading
core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java +48 −1 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ public final class TextViewAssertions { * @param selection The expected selection. */ public static ViewAssertion hasSelection(String selection) { return new TextSelectionAssertion(is(selection)); return hasSelection(is(selection)); } /** Loading @@ -65,6 +65,53 @@ public final class TextViewAssertions { return new TextSelectionAssertion(selection); } /** * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at * a specified index.<br> * <br> * View constraints: * <ul> * <li>must be a text view displayed on screen * <ul> * * @param index The expected index. */ public static ViewAssertion hasInsertionPointerAtIndex(int index) { return hasInsertionPointerAtIndex(is(index)); } /** * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at * a specified index.<br> * <br> * View constraints: * <ul> * <li>must be a text view displayed on screen * <ul> * * @param index A matcher representing the expected index. */ public static ViewAssertion hasInsertionPointerAtIndex(final Matcher<Integer> index) { return new ViewAssertion() { @Override public void check(View view, NoMatchingViewException exception) { if (view instanceof TextView) { TextView textView = (TextView) view; int selectionStart = textView.getSelectionStart(); int selectionEnd = textView.getSelectionEnd(); try { assertThat(selectionStart, index); assertThat(selectionEnd, index); } catch (IndexOutOfBoundsException e) { throw new AssertionFailedError(e.getMessage()); } } else { throw new AssertionFailedError("TextView not found"); } } }; } /** * A {@link ViewAssertion} to check the selected text in a {@link TextView}. */ Loading