@@ -60,7 +60,6 @@ private DrawerActions() {
6060 }
6161
6262 private abstract static class DrawerAction implements ViewAction {
63-
6463 @ Override
6564 public final Matcher <View > getConstraints () {
6665 return isAssignableFrom (DrawerLayout .class );
@@ -84,7 +83,6 @@ public final void perform(UiController uiController, View view) {
8483 drawer .addDrawerListener (idlingListener );
8584 IdlingRegistry .getInstance ().register (idlingListener );
8685 }
87-
8886 performAction (uiController , drawer );
8987 uiController .loopMainThreadUntilIdle ();
9088
@@ -194,17 +192,81 @@ protected Matcher<View> checkAction() {
194192 }
195193
196194 @ Override
197- protected void performAction (UiController uiController , DrawerLayout view ) {
198- view .closeDrawer (gravity );
195+ public void performAction (UiController uiController , DrawerLayout drawer ) {
196+ IdlingDrawerClosedListener closeListener = new IdlingDrawerClosedListener ();
197+ drawer .addDrawerListener (closeListener );
198+ drawer .closeDrawer (gravity );
199199 uiController .loopMainThreadUntilIdle ();
200- // If still open wait some more...
201- if (view .isDrawerVisible (gravity )) {
202- uiController .loopMainThreadForAtLeast (300 );
203- }
200+ // Need to wait extra time after it closes to reduce flakiness.
201+ uiController .loopMainThreadForAtLeast (300 );
202+ drawer .removeDrawerListener (closeListener );
203+ }
204+ };
205+ }
206+
207+ /**
208+ * Creates an action that will wait for the drawer to close. Use this in cases where the closing
209+ * of the drawer is implicit, such as selecting an item in the drawer. No operation if the drawer
210+ * is closed. This uses an idling resource to wait for close, so it will fail if it does not close
211+ * within the idling resource timeout.
212+ */
213+ public static ViewAction waitForClose () {
214+ return new DrawerAction () {
215+ @ Override
216+ public String getDescription () {
217+ return "waiting for drawer to close" ;
218+ }
219+
220+ @ Override
221+ protected Matcher <View > checkAction () {
222+ return isOpen ();
223+ }
224+
225+ @ Override
226+ public void performAction (UiController uiController , DrawerLayout drawer ) {
227+ // Add a listener that waits for the drawer to be closed, wait for it to idle,
228+ // and then remove the listener immediately.
229+ IdlingDrawerClosedListener closeListener = new IdlingDrawerClosedListener ();
230+ drawer .addDrawerListener (closeListener );
231+ uiController .loopMainThreadUntilIdle ();
232+ drawer .removeDrawerListener (closeListener );
204233 }
205234 };
206235 }
207236
237+ /** Drawer listener that functions as an {@link IdlingResource} for Espresso. */
238+ private static final class IdlingDrawerClosedListener extends SimpleDrawerListener
239+ implements IdlingResource {
240+
241+ private final int id = nextId .getAndIncrement ();
242+
243+ private ResourceCallback callback ;
244+ private boolean isClosed = false ;
245+
246+ @ Override
247+ public void onDrawerClosed (View view ) {
248+ isClosed = true ;
249+ if (callback != null ) {
250+ callback .onTransitionToIdle ();
251+ }
252+ }
253+
254+ @ Override
255+ public String getName () {
256+ return "IdlingDrawerListener::" + id ;
257+ }
258+
259+ @ Override
260+ public boolean isIdleNow () {
261+ return isClosed ;
262+ }
263+
264+ @ Override
265+ public void registerIdleTransitionCallback (ResourceCallback callback ) {
266+ this .callback = callback ;
267+ }
268+ }
269+
208270 /** Drawer listener that functions as an {@link IdlingResource} for Espresso. */
209271 private static final class IdlingDrawerListener extends SimpleDrawerListener
210272 implements IdlingResource {
0 commit comments