blob: 3825e3f3f9ea96a0cbc5f7a6576ddc33572ae4be [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;
22import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080023import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010024import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080025import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080026import static android.support.test.espresso.matcher.ViewMatchers.withId;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010027import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +090028import static android.support.test.espresso.matcher.ViewMatchers.withText;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010029
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080030import static org.hamcrest.Matchers.allOf;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010031import static org.hamcrest.Matchers.is;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010032
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080033import android.support.test.espresso.NoMatchingRootException;
34import android.support.test.espresso.NoMatchingViewException;
35import android.support.test.espresso.UiController;
36import android.support.test.espresso.ViewAction;
37import android.support.test.espresso.ViewInteraction;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010038import android.view.MenuItem;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080039import android.view.View;
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010040import android.view.ViewGroup;
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080041
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010042import com.android.internal.widget.FloatingToolbar;
43
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +010044import org.hamcrest.Description;
45import org.hamcrest.Matcher;
46import org.hamcrest.TypeSafeMatcher;
47
48import java.util.ArrayList;
49import java.util.List;
50
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010051/**
52 * Espresso utility methods for the floating toolbar.
53 */
54public class FloatingToolbarEspressoUtils {
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080055 private final static Object TAG = FloatingToolbar.FLOATING_TOOLBAR_TAG;
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010056
57 private FloatingToolbarEspressoUtils() {}
58
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080059 private static ViewInteraction onFloatingToolBar() {
60 return onView(withTagValue(is(TAG)))
61 .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG)))));
62 }
63
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010064 /**
Siyamed Sinir987ec652016-02-17 19:44:41 -080065 * Creates a {@link ViewInteraction} for the floating bar menu item with the given matcher.
66 *
67 * @param matcher The matcher for the menu item.
68 */
69 public static ViewInteraction onFloatingToolBarItem(Matcher<View> matcher) {
70 return onView(matcher)
71 .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG)))));
72 }
73
74 /**
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010075 * Asserts that the floating toolbar is displayed on screen.
76 *
77 * @throws AssertionError if the assertion fails
78 */
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080079 public static void assertFloatingToolbarIsDisplayed() {
80 onFloatingToolBar().check(matches(isDisplayed()));
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +010081 }
82
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -080083 /**
84 * Asserts that the floating toolbar is not displayed on screen.
85 *
86 * @throws AssertionError if the assertion fails
87 */
88 public static void assertFloatingToolbarIsNotDisplayed() {
89 try {
90 onFloatingToolBar().check(matches(isDisplayed()));
91 } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
92 return;
93 }
94 throw new AssertionError("Floating toolbar is displayed");
95 }
96
97 private static void toggleOverflow() {
98 final int id = com.android.internal.R.id.overflow;
99 onView(allOf(withId(id), isDisplayed()))
100 .inRoot(withDecorView(hasDescendant(withId(id))))
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900101 .perform(click());
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800102 onView(isRoot()).perform(SLEEP);
103 }
104
105 public static void sleepForFloatingToolbarPopup() {
106 onView(isRoot()).perform(SLEEP);
107 }
108
109 /**
110 * Asserts that the floating toolbar contains the specified item.
111 *
112 * @param itemLabel label of the item.
113 * @throws AssertionError if the assertion fails
114 */
115 public static void assertFloatingToolbarContainsItem(String itemLabel) {
116 try{
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900117 onFloatingToolBar().check(matches(hasDescendant(withText(itemLabel))));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800118 } catch (AssertionError e) {
119 try{
120 toggleOverflow();
121 } catch (NoMatchingViewException | NoMatchingRootException e2) {
122 // No overflow items.
123 throw e;
124 }
125 try{
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900126 onFloatingToolBar().check(matches(hasDescendant(withText(itemLabel))));
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800127 } finally {
128 toggleOverflow();
129 }
130 }
131 }
132
133 /**
Abodunrinwa Toki6eecdc92017-04-11 05:15:25 +0100134 * Asserts that the floating toolbar contains a specified item at a specified index.
135 *
136 * @param menuItemId id of the menu item
137 * @param index expected index of the menu item in the floating toolbar
138 * @throws AssertionError if the assertion fails
139 */
140 public static void assertFloatingToolbarItemIndex(final int menuItemId, final int index) {
141 onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
142 private List<Integer> menuItemIds = new ArrayList<>();
143
144 @Override
145 public boolean matchesSafely(View view) {
146 collectMenuItemIds(view);
147 return menuItemIds.size() > index && menuItemIds.get(index) == menuItemId;
148 }
149
150 @Override
151 public void describeTo(Description description) {}
152
153 private void collectMenuItemIds(View view) {
154 if (view.getTag() instanceof MenuItem) {
155 menuItemIds.add(((MenuItem) view.getTag()).getItemId());
156 } else if (view instanceof ViewGroup) {
157 ViewGroup viewGroup = (ViewGroup) view;
158 for (int i = 0; i < viewGroup.getChildCount(); i++) {
159 collectMenuItemIds(viewGroup.getChildAt(i));
160 }
161 }
162 }
163 }));
164 }
165
166 /**
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800167 * Asserts that the floating toolbar doesn't contain the specified item.
168 *
169 * @param itemLabel label of the item.
170 * @throws AssertionError if the assertion fails
171 */
172 public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
173 try{
174 assertFloatingToolbarContainsItem(itemLabel);
175 } catch (AssertionError e) {
176 return;
177 }
178 throw new AssertionError("Floating toolbar contains " + itemLabel);
179 }
180
181 /**
Abodunrinwa Toki76b51dc2017-07-13 23:37:11 +0100182 * Asserts that the floating toolbar does not contain a menu item with the specified id.
183 *
184 * @param menuItemId id of the menu item
185 * @throws AssertionError if the assertion fails
186 */
187 public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
188 onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
189 @Override
190 public boolean matchesSafely(View view) {
191 return !hasMenuItemWithSpecifiedId(view);
192 }
193
194 @Override
195 public void describeTo(Description description) {}
196
197 private boolean hasMenuItemWithSpecifiedId(View view) {
198 if (view.getTag() instanceof MenuItem
199 && ((MenuItem) view.getTag()).getItemId() == menuItemId) {
200 return true;
201 } else if (view instanceof ViewGroup) {
202 ViewGroup viewGroup = (ViewGroup) view;
203 for (int i = 0; i < viewGroup.getChildCount(); i++) {
204 if (hasMenuItemWithSpecifiedId(viewGroup.getChildAt(i))) {
205 return true;
206 }
207 }
208 }
209 return false;
210 }
211 }));
212 }
213
214 /**
Keisuke Kuroyanagi31eb74f2016-04-06 19:37:46 +0900215 * Click specified item on the floating tool bar.
216 *
217 * @param itemLabel label of the item.
218 */
219 public static void clickFloatingToolbarItem(String itemLabel) {
220 try{
221 onFloatingToolBarItem(withText(itemLabel)).check(matches(isDisplayed()));
222 } catch (AssertionError e) {
223 // Try to find the item in the overflow menu.
224 toggleOverflow();
225 }
226 onFloatingToolBarItem(withText(itemLabel)).perform(click());
227 }
228
229 /**
Keisuke Kuroyanagib0dd77c2015-12-02 13:27:01 -0800230 * ViewAction to sleep to wait floating toolbar's animation.
231 */
232 private static final ViewAction SLEEP = new ViewAction() {
233 private static final long SLEEP_DURATION = 400;
234
235 @Override
236 public Matcher<View> getConstraints() {
237 return isDisplayed();
238 }
239
240 @Override
241 public String getDescription() {
242 return "Sleep " + SLEEP_DURATION + " ms.";
243 }
244
245 @Override
246 public void perform(UiController uiController, View view) {
247 uiController.loopMainThreadForAtLeast(SLEEP_DURATION);
248 }
249 };
Abodunrinwa Toki8a5e1ae2015-09-28 21:59:04 +0100250}