Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -2270,6 +2270,7 @@ <!-- Floating toolbar --> <java-symbol type="id" name="floating_toolbar_menu_item_image_button" /> <java-symbol type="id" name="overflow" /> <java-symbol type="layout" name="floating_popup_container" /> <java-symbol type="layout" name="floating_popup_menu_button" /> <java-symbol type="layout" name="floating_popup_open_overflow_button" /> Loading core/tests/coretests/src/android/widget/TextViewActivityTest.java +75 −15 Original line number Diff line number Diff line Loading @@ -28,6 +28,10 @@ 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.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem; 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 @@ -149,19 +153,75 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV @SmallTest public void testToolbarAppearsAfterSelection() throws Exception { // 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()); assertFloatingToolbarIsNotDisplayed(); 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()); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); final String text2 = "Toolbar disappears after typing text."; onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2)); assertFloatingToolbarIsNotDisplayed(); } @SmallTest public void testToolbarAndInsertionHandle() throws Exception { final String text = "text"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length())); assertFloatingToolbarIsNotDisplayed(); onHandleView(com.android.internal.R.id.insertion_handle).perform(click()); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.selectAll)); assertFloatingToolbarDoesNotContainItem( getActivity().getString(com.android.internal.R.string.copy)); assertFloatingToolbarDoesNotContainItem( getActivity().getString(com.android.internal.R.string.cut)); } @SmallTest public void testToolbarAndSelectionHandle() throws Exception { final String text = "abcd efg hijk"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f"))); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.selectAll)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.copy)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.cut)); final TextView textView = (TextView) getActivity().findViewById(R.id.textview); onHandleView(com.android.internal.R.id.selection_start_handle) .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a'))); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); onHandleView(com.android.internal.R.id.selection_end_handle) .perform(dragHandle(textView, Handle.SELECTION_END, text.length())); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); assertFloatingToolbarDoesNotContainItem( getActivity().getString(com.android.internal.R.string.selectAll)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.copy)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.cut)); } @SmallTest Loading core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java +109 −7 Original line number Diff line number Diff line Loading @@ -19,31 +19,133 @@ 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.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static android.support.test.espresso.matcher.ViewMatchers.withTagValue; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import android.app.Activity; import org.hamcrest.Matcher; import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewInteraction; import android.support.test.espresso.action.ViewActions; import android.support.test.espresso.matcher.ViewMatchers; import android.view.View; import com.android.internal.widget.FloatingToolbar; /** * Espresso utility methods for the floating toolbar. */ public class FloatingToolbarEspressoUtils { private final static Object TAG = FloatingToolbar.FLOATING_TOOLBAR_TAG; private FloatingToolbarEspressoUtils() {} private static ViewInteraction onFloatingToolBar() { return onView(withTagValue(is(TAG))) .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG))))); } /** * 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())); public static void assertFloatingToolbarIsDisplayed() { onFloatingToolBar().check(matches(isDisplayed())); } /** * Asserts that the floating toolbar is not displayed on screen. * * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarIsNotDisplayed() { try { onFloatingToolBar().check(matches(isDisplayed())); } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) { return; } throw new AssertionError("Floating toolbar is displayed"); } private static void toggleOverflow() { final int id = com.android.internal.R.id.overflow; onView(allOf(withId(id), isDisplayed())) .inRoot(withDecorView(hasDescendant(withId(id)))) .perform(ViewActions.click()); onView(isRoot()).perform(SLEEP); } public static void sleepForFloatingToolbarPopup() { onView(isRoot()).perform(SLEEP); } /** * Asserts that the floating toolbar contains the specified item. * * @param itemLabel label of the item. * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarContainsItem(String itemLabel) { try{ onFloatingToolBar().check(matches(hasDescendant(ViewMatchers.withText(itemLabel)))); } catch (AssertionError e) { try{ toggleOverflow(); } catch (NoMatchingViewException | NoMatchingRootException e2) { // No overflow items. throw e; } try{ onFloatingToolBar().check(matches(hasDescendant(ViewMatchers.withText(itemLabel)))); } finally { toggleOverflow(); } } } /** * Asserts that the floating toolbar doesn't contain the specified item. * * @param itemLabel label of the item. * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) { try{ assertFloatingToolbarContainsItem(itemLabel); } catch (AssertionError e) { return; } throw new AssertionError("Floating toolbar contains " + itemLabel); } /** * ViewAction to sleep to wait floating toolbar's animation. */ private static final ViewAction SLEEP = new ViewAction() { private static final long SLEEP_DURATION = 400; @Override public Matcher<View> getConstraints() { return isDisplayed(); } @Override public String getDescription() { return "Sleep " + SLEEP_DURATION + " ms."; } @Override public void perform(UiController uiController, View view) { uiController.loopMainThreadForAtLeast(SLEEP_DURATION); } }; } Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -2270,6 +2270,7 @@ <!-- Floating toolbar --> <java-symbol type="id" name="floating_toolbar_menu_item_image_button" /> <java-symbol type="id" name="overflow" /> <java-symbol type="layout" name="floating_popup_container" /> <java-symbol type="layout" name="floating_popup_menu_button" /> <java-symbol type="layout" name="floating_popup_open_overflow_button" /> Loading
core/tests/coretests/src/android/widget/TextViewActivityTest.java +75 −15 Original line number Diff line number Diff line Loading @@ -28,6 +28,10 @@ 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.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem; 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 @@ -149,19 +153,75 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV @SmallTest public void testToolbarAppearsAfterSelection() throws Exception { // 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()); assertFloatingToolbarIsNotDisplayed(); 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()); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); final String text2 = "Toolbar disappears after typing text."; onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2)); assertFloatingToolbarIsNotDisplayed(); } @SmallTest public void testToolbarAndInsertionHandle() throws Exception { final String text = "text"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length())); assertFloatingToolbarIsNotDisplayed(); onHandleView(com.android.internal.R.id.insertion_handle).perform(click()); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.selectAll)); assertFloatingToolbarDoesNotContainItem( getActivity().getString(com.android.internal.R.string.copy)); assertFloatingToolbarDoesNotContainItem( getActivity().getString(com.android.internal.R.string.cut)); } @SmallTest public void testToolbarAndSelectionHandle() throws Exception { final String text = "abcd efg hijk"; onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f"))); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.selectAll)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.copy)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.cut)); final TextView textView = (TextView) getActivity().findViewById(R.id.textview); onHandleView(com.android.internal.R.id.selection_start_handle) .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a'))); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); onHandleView(com.android.internal.R.id.selection_end_handle) .perform(dragHandle(textView, Handle.SELECTION_END, text.length())); sleepForFloatingToolbarPopup(); assertFloatingToolbarIsDisplayed(); assertFloatingToolbarDoesNotContainItem( getActivity().getString(com.android.internal.R.string.selectAll)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.copy)); assertFloatingToolbarContainsItem( getActivity().getString(com.android.internal.R.string.cut)); } @SmallTest Loading
core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java +109 −7 Original line number Diff line number Diff line Loading @@ -19,31 +19,133 @@ 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.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static android.support.test.espresso.matcher.ViewMatchers.withTagValue; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import android.app.Activity; import org.hamcrest.Matcher; import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewInteraction; import android.support.test.espresso.action.ViewActions; import android.support.test.espresso.matcher.ViewMatchers; import android.view.View; import com.android.internal.widget.FloatingToolbar; /** * Espresso utility methods for the floating toolbar. */ public class FloatingToolbarEspressoUtils { private final static Object TAG = FloatingToolbar.FLOATING_TOOLBAR_TAG; private FloatingToolbarEspressoUtils() {} private static ViewInteraction onFloatingToolBar() { return onView(withTagValue(is(TAG))) .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG))))); } /** * 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())); public static void assertFloatingToolbarIsDisplayed() { onFloatingToolBar().check(matches(isDisplayed())); } /** * Asserts that the floating toolbar is not displayed on screen. * * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarIsNotDisplayed() { try { onFloatingToolBar().check(matches(isDisplayed())); } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) { return; } throw new AssertionError("Floating toolbar is displayed"); } private static void toggleOverflow() { final int id = com.android.internal.R.id.overflow; onView(allOf(withId(id), isDisplayed())) .inRoot(withDecorView(hasDescendant(withId(id)))) .perform(ViewActions.click()); onView(isRoot()).perform(SLEEP); } public static void sleepForFloatingToolbarPopup() { onView(isRoot()).perform(SLEEP); } /** * Asserts that the floating toolbar contains the specified item. * * @param itemLabel label of the item. * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarContainsItem(String itemLabel) { try{ onFloatingToolBar().check(matches(hasDescendant(ViewMatchers.withText(itemLabel)))); } catch (AssertionError e) { try{ toggleOverflow(); } catch (NoMatchingViewException | NoMatchingRootException e2) { // No overflow items. throw e; } try{ onFloatingToolBar().check(matches(hasDescendant(ViewMatchers.withText(itemLabel)))); } finally { toggleOverflow(); } } } /** * Asserts that the floating toolbar doesn't contain the specified item. * * @param itemLabel label of the item. * @throws AssertionError if the assertion fails */ public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) { try{ assertFloatingToolbarContainsItem(itemLabel); } catch (AssertionError e) { return; } throw new AssertionError("Floating toolbar contains " + itemLabel); } /** * ViewAction to sleep to wait floating toolbar's animation. */ private static final ViewAction SLEEP = new ViewAction() { private static final long SLEEP_DURATION = 400; @Override public Matcher<View> getConstraints() { return isDisplayed(); } @Override public String getDescription() { return "Sleep " + SLEEP_DURATION + " ms."; } @Override public void perform(UiController uiController, View view) { uiController.loopMainThreadForAtLeast(SLEEP_DURATION); } }; }