blob: f7069b31710feb55a85e1e5aed25963e5d483993 [file] [log] [blame]
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package android.widget.espresso;
18
19import static android.support.test.espresso.Espresso.onView;
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +090020import static android.support.test.espresso.action.ViewActions.click;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010021import static android.support.test.espresso.assertion.ViewAssertions.matches;
Abodunrinwa Toki4a056a52017-08-05 01:56:40 +010022import static android.support.test.espresso.matcher.RootMatchers.isPlatformPopup;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010023import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080024import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010025import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080026import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080027import static android.support.test.espresso.matcher.ViewMatchers.withId;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010028import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +090029import static android.support.test.espresso.matcher.ViewMatchers.withText;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010030
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080031import static org.hamcrest.Matchers.allOf;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010032import static org.hamcrest.Matchers.is;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010033
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080034import android.support.test.espresso.NoMatchingRootException;
35import android.support.test.espresso.NoMatchingViewException;
36import android.support.test.espresso.UiController;
37import android.support.test.espresso.ViewAction;
38import android.support.test.espresso.ViewInteraction;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010039import android.view.MenuItem;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080040import android.view.View;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010041import android.view.ViewGroup;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080042
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010043import com.android.internal.widget.FloatingToolbar;
44
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010045import org.hamcrest.Description;
46import org.hamcrest.Matcher;
47import org.hamcrest.TypeSafeMatcher;
48
49import java.util.ArrayList;
50import java.util.List;
51
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010052/**
53 * Espresso utility methods for the floating toolbar.
54 */
55public class FloatingToolbarEspressoUtils {
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080056 private final static Object TAG = FloatingToolbar.FLOATING_TOOLBAR_TAG;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010057
58 private FloatingToolbarEspressoUtils() {}
59
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080060 private static ViewInteraction onFloatingToolBar() {
61 return onView(withTagValue(is(TAG)))
Abodunrinwa Toki4a056a52017-08-05 01:56:40 +010062 .inRoot(allOf(
63 isPlatformPopup(),
64 withDecorView(hasDescendant(withTagValue(is(TAG))))));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080065 }
66
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010067 /**
Siyamed Sinir987ec652016-02-17 19:44:41 -080068 * Creates a {@link ViewInteraction} for the floating bar menu item with the given matcher.
69 *
70 * @param matcher The matcher for the menu item.
71 */
72 public static ViewInteraction onFloatingToolBarItem(Matcher<View> matcher) {
73 return onView(matcher)
74 .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG)))));
75 }
76
77 /**
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010078 * Asserts that the floating toolbar is displayed on screen.
79 *
80 * @throws AssertionError if the assertion fails
81 */
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080082 public static void assertFloatingToolbarIsDisplayed() {
83 onFloatingToolBar().check(matches(isDisplayed()));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010084 }
85
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080086 /**
87 * Asserts that the floating toolbar is not displayed on screen.
88 *
89 * @throws AssertionError if the assertion fails
90 */
91 public static void assertFloatingToolbarIsNotDisplayed() {
92 try {
93 onFloatingToolBar().check(matches(isDisplayed()));
94 } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
95 return;
96 }
97 throw new AssertionError("Floating toolbar is displayed");
98 }
99
100 private static void toggleOverflow() {
101 final int id = com.android.internal.R.id.overflow;
102 onView(allOf(withId(id), isDisplayed()))
103 .inRoot(withDecorView(hasDescendant(withId(id))))
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900104 .perform(click());
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800105 onView(isRoot()).perform(SLEEP);
106 }
107
108 public static void sleepForFloatingToolbarPopup() {
109 onView(isRoot()).perform(SLEEP);
110 }
111
112 /**
113 * Asserts that the floating toolbar contains the specified item.
114 *
115 * @param itemLabel label of the item.
116 * @throws AssertionError if the assertion fails
117 */
118 public static void assertFloatingToolbarContainsItem(String itemLabel) {
119 try{
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900120 onFloatingToolBar().check(matches(hasDescendant(withText(itemLabel))));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800121 } catch (AssertionError e) {
122 try{
123 toggleOverflow();
124 } catch (NoMatchingViewException | NoMatchingRootException e2) {
125 // No overflow items.
126 throw e;
127 }
128 try{
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900129 onFloatingToolBar().check(matches(hasDescendant(withText(itemLabel))));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800130 } finally {
131 toggleOverflow();
132 }
133 }
134 }
135
136 /**
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100137 * Asserts that the floating toolbar contains a specified item at a specified index.
138 *
139 * @param menuItemId id of the menu item
140 * @param index expected index of the menu item in the floating toolbar
141 * @throws AssertionError if the assertion fails
142 */
143 public static void assertFloatingToolbarItemIndex(final int menuItemId, final int index) {
144 onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
145 private List<Integer> menuItemIds = new ArrayList<>();
146
147 @Override
148 public boolean matchesSafely(View view) {
149 collectMenuItemIds(view);
150 return menuItemIds.size() > index && menuItemIds.get(index) == menuItemId;
151 }
152
153 @Override
154 public void describeTo(Description description) {}
155
156 private void collectMenuItemIds(View view) {
157 if (view.getTag() instanceof MenuItem) {
158 menuItemIds.add(((MenuItem) view.getTag()).getItemId());
159 } else if (view instanceof ViewGroup) {
160 ViewGroup viewGroup = (ViewGroup) view;
161 for (int i = 0; i < viewGroup.getChildCount(); i++) {
162 collectMenuItemIds(viewGroup.getChildAt(i));
163 }
164 }
165 }
166 }));
167 }
168
169 /**
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800170 * Asserts that the floating toolbar doesn't contain the specified item.
171 *
172 * @param itemLabel label of the item.
173 * @throws AssertionError if the assertion fails
174 */
175 public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
176 try{
177 assertFloatingToolbarContainsItem(itemLabel);
178 } catch (AssertionError e) {
179 return;
180 }
181 throw new AssertionError("Floating toolbar contains " + itemLabel);
182 }
183
184 /**
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +0100185 * Asserts that the floating toolbar does not contain a menu item with the specified id.
186 *
187 * @param menuItemId id of the menu item
188 * @throws AssertionError if the assertion fails
189 */
190 public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
191 onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
192 @Override
193 public boolean matchesSafely(View view) {
194 return !hasMenuItemWithSpecifiedId(view);
195 }
196
197 @Override
198 public void describeTo(Description description) {}
199
200 private boolean hasMenuItemWithSpecifiedId(View view) {
201 if (view.getTag() instanceof MenuItem
202 && ((MenuItem) view.getTag()).getItemId() == menuItemId) {
203 return true;
204 } else if (view instanceof ViewGroup) {
205 ViewGroup viewGroup = (ViewGroup) view;
206 for (int i = 0; i < viewGroup.getChildCount(); i++) {
207 if (hasMenuItemWithSpecifiedId(viewGroup.getChildAt(i))) {
208 return true;
209 }
210 }
211 }
212 return false;
213 }
214 }));
215 }
216
217 /**
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900218 * Click specified item on the floating tool bar.
219 *
220 * @param itemLabel label of the item.
221 */
222 public static void clickFloatingToolbarItem(String itemLabel) {
223 try{
224 onFloatingToolBarItem(withText(itemLabel)).check(matches(isDisplayed()));
225 } catch (AssertionError e) {
226 // Try to find the item in the overflow menu.
227 toggleOverflow();
228 }
229 onFloatingToolBarItem(withText(itemLabel)).perform(click());
230 }
231
232 /**
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800233 * ViewAction to sleep to wait floating toolbar's animation.
234 */
235 private static final ViewAction SLEEP = new ViewAction() {
236 private static final long SLEEP_DURATION = 400;
237
238 @Override
239 public Matcher<View> getConstraints() {
240 return isDisplayed();
241 }
242
243 @Override
244 public String getDescription() {
245 return "Sleep " + SLEEP_DURATION + " ms.";
246 }
247
248 @Override
249 public void perform(UiController uiController, View view) {
250 uiController.loopMainThreadForAtLeast(SLEEP_DURATION);
251 }
252 };
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100253}