136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley/*
236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * Copyright (C) 2017 The Android Open Source Project
336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley *
436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * Licensed under the Apache License, Version 2.0 (the "License");
536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * you may not use this file except in compliance with the License.
636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * You may obtain a copy of the License at
736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley *
836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley *      http://www.apache.org/licenses/LICENSE-2.0
936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley *
1036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * Unless required by applicable law or agreed to in writing, software
1136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * distributed under the License is distributed on an "AS IS" BASIS,
1236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * See the License for the specific language governing permissions and
1436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * limitations under the License.
1536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley */
1636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
1736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleypackage android.support.wear.widget.drawer;
1836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
1936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.Espresso.onView;
2036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.action.ViewActions.click;
2136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.action.ViewActions.swipeDown;
2236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.assertion.ViewAssertions.matches;
2331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
2436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
2536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
2636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.matcher.ViewMatchers.withId;
2731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport static android.support.test.espresso.matcher.ViewMatchers.withParent;
2836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.test.espresso.matcher.ViewMatchers.withText;
2936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static android.support.wear.widget.util.AsyncViewActions.waitForMatchingView;
3036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
3136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.hamcrest.Matchers.allOf;
3231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport static org.hamcrest.Matchers.is;
3336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.hamcrest.Matchers.not;
3436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.junit.Assert.assertNotNull;
3536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.junit.Assert.assertTrue;
3636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.mockito.Matchers.any;
3736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.mockito.Mockito.mock;
3836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport static org.mockito.Mockito.verify;
3936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
4036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.content.Intent;
4131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.support.test.espresso.PerformException;
4231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.support.test.espresso.UiController;
4331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.support.test.espresso.ViewAction;
4431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.support.test.espresso.util.HumanReadables;
4531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.support.test.espresso.util.TreeIterables;
4636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.support.test.filters.LargeTest;
4736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.support.test.rule.ActivityTestRule;
4836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.support.test.runner.AndroidJUnit4;
4936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.support.v7.widget.RecyclerView;
5036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.support.wear.test.R;
5136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.support.wear.widget.drawer.DrawerTestActivity.DrawerStyle;
5231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.view.Menu;
5336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.view.MenuItem;
5436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.view.MenuItem.OnMenuItemClickListener;
5536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.view.View;
5636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport android.widget.ImageView;
5731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport android.widget.TextView;
5836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
5936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport org.hamcrest.Description;
6031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport org.hamcrest.Matcher;
6136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport org.hamcrest.TypeSafeMatcher;
625c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelleyimport org.junit.Before;
6336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport org.junit.Rule;
6436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport org.junit.Test;
6536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleyimport org.junit.runner.RunWith;
665c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelleyimport org.mockito.Mock;
675c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelleyimport org.mockito.MockitoAnnotations;
6836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
6931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport java.util.concurrent.TimeoutException;
7031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
7131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelleyimport javax.annotation.Nullable;
7231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
7336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley/**
7436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley * Espresso tests for {@link WearableDrawerLayout}.
7536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley */
7636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley@LargeTest
7736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley@RunWith(AndroidJUnit4.class)
7836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelleypublic class WearableDrawerLayoutEspressoTest {
7936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
8036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private static final long MAX_WAIT_MS = 4000;
8136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
8236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Rule public final ActivityTestRule<DrawerTestActivity> activityRule =
8336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            new ActivityTestRule<>(
8436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                    DrawerTestActivity.class, true /* touchMode */, false /* initialLaunch*/);
8536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
8636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private final Intent mSinglePageIntent =
8736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            new DrawerTestActivity.Builder().setStyle(DrawerStyle.BOTH_DRAWER_NAV_SINGLE_PAGE)
8836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                    .build();
895c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    @Mock WearableNavigationDrawerView.OnItemSelectedListener mNavDrawerItemSelectedListener;
9036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
915c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    @Before
925c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    public void setUp() {
935c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        MockitoAnnotations.initMocks(this);
9436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
9536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
9636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
9736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void openingNavigationDrawerDoesNotCloseActionDrawer() {
9836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a drawer layout with a peeking action and navigation drawer
9936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
10036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        DrawerTestActivity activity = activityRule.getActivity();
10136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        WearableDrawerView actionDrawer =
10236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                (WearableDrawerView) activity.findViewById(R.id.action_drawer);
10336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        WearableDrawerView navigationDrawer =
10436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                (WearableDrawerView) activity.findViewById(R.id.navigation_drawer);
10536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        assertTrue(actionDrawer.isPeeking());
10636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        assertTrue(navigationDrawer.isPeeking());
10736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
10836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN the top drawer is opened
10936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        openDrawer(navigationDrawer);
11036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer))
11136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
11236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
11336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                allOf(withId(R.id.navigation_drawer), isOpened(true)),
11436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
11536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
11636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the action drawer should still be peeking
11736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        assertTrue(actionDrawer.isPeeking());
11836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
11936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
12036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
12136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void swipingDownNavigationDrawerDoesNotCloseActionDrawer() {
12236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a drawer layout with a peeking action and navigation drawer
12336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
12436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer)).check(matches(isPeeking()));
12536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer)).check(matches(isPeeking()));
12636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
12736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN the top drawer is opened by swiping down
12836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.drawer_layout)).perform(swipeDown());
12936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer))
13036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
13136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
13236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                allOf(withId(R.id.navigation_drawer), isOpened(true)),
13336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
13436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
13536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the action drawer should still be peeking
13636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer)).check(matches(isPeeking()));
13736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
13836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
13936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
14036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
14136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void firstNavDrawerItemShouldBeSelectedInitially() {
14236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a top drawer
14336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN it is first opened
14436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
14536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.drawer_layout)).perform(swipeDown());
14636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer))
14736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
14836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
14936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                allOf(withId(R.id.navigation_drawer), isOpened(true)),
15036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
15136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
15236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the text should display "0".
15397f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska        onView(withId(R.id.ws_nav_drawer_text)).check(matches(withText("0")));
15436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
15536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
15636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
15736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void selectingNavItemChangesTextAndClosedDrawer() {
15836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN an open top drawer
15936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
16036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.drawer_layout)).perform(swipeDown());
16136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer))
16236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
16336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
16436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                allOf(withId(R.id.navigation_drawer), isOpened(true)),
16536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
16636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
16736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN the second item is selected
16897f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska        onView(withId(R.id.ws_nav_drawer_icon_1)).perform(click());
16936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
17036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the text should display "1" and it should close.
17197f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska        onView(withId(R.id.ws_nav_drawer_text))
17236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
17336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
17497f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska                                allOf(withId(R.id.ws_nav_drawer_text), withText("1")),
17536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
17636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer))
17736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
17836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
17936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                allOf(withId(R.id.navigation_drawer), isClosed(true)),
18036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
18136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
18236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
18336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
1845c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    public void programmaticallySelectingNavItemChangesTextInSinglePage() {
1855c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        // GIVEN an open top drawer
1865c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        activityRule.launchActivity(new DrawerTestActivity.Builder()
1875c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .setStyle(DrawerStyle.BOTH_DRAWER_NAV_SINGLE_PAGE)
1885c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .openTopDrawerInOnCreate()
1895c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .build());
1905c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        final WearableNavigationDrawerView navDrawer =
1915c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                activityRule.getActivity().findViewById(R.id.navigation_drawer);
1925c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        navDrawer.addOnItemSelectedListener(mNavDrawerItemSelectedListener);
1935c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
1945c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        // WHEN the second item is selected programmatically
1955c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        selectNavItem(navDrawer, 1);
1965c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
1975c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        // THEN the text should display "1" and the listener should be notified.
19897f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska        onView(withId(R.id.ws_nav_drawer_text))
1995c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .check(matches(withText("1")));
2005c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        verify(mNavDrawerItemSelectedListener).onItemSelected(1);
2015c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    }
2025c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
2035c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    @Test
2045c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    public void programmaticallySelectingNavItemChangesTextInMultiPage() {
2055c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        // GIVEN an open top drawer
2065c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        activityRule.launchActivity(new DrawerTestActivity.Builder()
2075c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .setStyle(DrawerStyle.BOTH_DRAWER_NAV_MULTI_PAGE)
2085c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .openTopDrawerInOnCreate()
2095c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .build());
2105c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        final WearableNavigationDrawerView navDrawer =
2115c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                activityRule.getActivity().findViewById(R.id.navigation_drawer);
2125c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        navDrawer.addOnItemSelectedListener(mNavDrawerItemSelectedListener);
2135c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
2145c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        // WHEN the second item is selected programmatically
2155c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        selectNavItem(navDrawer, 1);
2165c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
2175c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        // THEN the text should display "1" and the listener should be notified.
21897f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska        onView(allOf(withId(R.id.ws_navigation_drawer_item_text), isDisplayed()))
2195c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                .check(matches(withText("1")));
2205c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        verify(mNavDrawerItemSelectedListener).onItemSelected(1);
2215c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    }
2225c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
2235c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    @Test
22436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void navDrawerShouldOpenWhenCalledInOnCreate() {
22536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN an activity which calls openDrawer(Gravity.TOP) in onCreate
22636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN it is launched
22736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(
22836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                new DrawerTestActivity.Builder()
22936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .setStyle(DrawerStyle.BOTH_DRAWER_NAV_SINGLE_PAGE)
23036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .openTopDrawerInOnCreate()
23136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .build());
23236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
23336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the nav drawer should be open
23436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer)).check(matches(isOpened(true)));
23536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
23636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
23736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
23836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void actionDrawerShouldOpenWhenCalledInOnCreate() {
23936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN an activity with only an action drawer which is opened in onCreate
24036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN it is launched
24136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(
24236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                new DrawerTestActivity.Builder()
24336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
24436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .openBottomDrawerInOnCreate()
24536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .build());
24636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
24736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the action drawer should be open
24836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer)).check(matches(isOpened(true)));
24936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
25036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
25136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
25236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void navDrawerShouldOpenWhenCalledInOnCreateAndThenCloseWhenRequested() {
25336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN an activity which calls openDrawer(Gravity.TOP) in onCreate, then closes it
25436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN it is launched
25536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(
25636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                new DrawerTestActivity.Builder()
25736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .setStyle(DrawerStyle.BOTH_DRAWER_NAV_SINGLE_PAGE)
25836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .openTopDrawerInOnCreate()
25936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .closeFirstDrawerOpened()
26036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .build());
26136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
26236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the nav drawer should be open and then close
26336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer))
26436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .check(matches(isOpened(true)))
26536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
26636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(
26736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                allOf(withId(R.id.navigation_drawer), isClosed(true)),
26836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
26936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
27036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
27136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
27236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void openedNavDrawerShouldPreventSwipeToClose() {
27336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN an activity which calls openDrawer(Gravity.TOP) in onCreate
27436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(
27536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                new DrawerTestActivity.Builder()
27636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .setStyle(DrawerStyle.BOTH_DRAWER_NAV_SINGLE_PAGE)
27736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .openTopDrawerInOnCreate()
27836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .build());
27936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
28036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the view should prevent swipe to close
28136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer)).check(matches(not(allowsSwipeToClose())));
28236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
28336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
28436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
28536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void closedNavDrawerShouldNotPreventSwipeToClose() {
28636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN an activity which doesn't start with the nav drawer open
28736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
28836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
28936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN the view should allow swipe to close
29036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.navigation_drawer)).check(matches(allowsSwipeToClose()));
29136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
29236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
29336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
29436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void scrolledDownActionDrawerCanScrollUpWhenReOpened() {
29536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a freshly launched activity
29636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
29736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        WearableActionDrawerView actionDrawer =
29836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                (WearableActionDrawerView) activityRule.getActivity()
29936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .findViewById(R.id.action_drawer);
30036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        RecyclerView recyclerView = (RecyclerView) actionDrawer.getDrawerContent();
30136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
30236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN the action drawer is opened and scrolled to the last item (Item 6)
30336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        openDrawer(actionDrawer);
30436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        scrollToPosition(recyclerView, 5);
30536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer))
30636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
30736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(allOf(withId(R.id.action_drawer), isOpened(true)),
30836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS))
30936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
31036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(allOf(withText("Item 6"), isCompletelyDisplayed()),
31136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
31236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // and then it is peeked
31336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        peekDrawer(actionDrawer);
31436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer))
31536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(waitForMatchingView(allOf(withId(R.id.action_drawer), isPeeking()),
31636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        MAX_WAIT_MS));
31736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // and re-opened
31836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        openDrawer(actionDrawer);
31936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer))
32036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(
32136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        waitForMatchingView(allOf(withId(R.id.action_drawer), isOpened(true)),
32236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                                MAX_WAIT_MS));
32336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
32436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN item 6 should be visible, but swiping down should scroll up, not close the drawer.
32536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withText("Item 6")).check(matches(isDisplayed()));
32636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer)).perform(swipeDown()).check(matches(isOpened(true)));
32736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
32836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
32936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
33036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void actionDrawerPeekIconShouldNotBeNull() {
33136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a drawer layout with a peeking action drawer whose menu is initialized in XML
33236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(mSinglePageIntent);
33336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        DrawerTestActivity activity = activityRule.getActivity();
33436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        ImageView peekIconView =
33536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                (ImageView) activity
33697f7aa4e4dd8f5c1f14d93d3f67540c72a5bbe57Aga Madurska                        .findViewById(R.id.ws_action_drawer_peek_action_icon);
33736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN its peek icon should not be null
33836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        assertNotNull(peekIconView.getDrawable());
33936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
34036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
34136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
34236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void tappingActionDrawerPeekIconShouldTriggerFirstAction() {
34336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a drawer layout with a peeking action drawer, title, and mock click listener
34436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(
34536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                new DrawerTestActivity.Builder()
34636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
34736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .build());
34836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        WearableActionDrawerView actionDrawer =
34936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                (WearableActionDrawerView) activityRule.getActivity()
35036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .findViewById(R.id.action_drawer);
35136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        OnMenuItemClickListener mockClickListener = mock(OnMenuItemClickListener.class);
35236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        actionDrawer.setOnMenuItemClickListener(mockClickListener);
35336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN the action drawer peek view is tapped
35469f9658a6e7f2ec1102ffc74bd19d053659cf392Sean Kelley        onView(withId(R.id.ws_drawer_view_peek_container))
35569f9658a6e7f2ec1102ffc74bd19d053659cf392Sean Kelley                .perform(waitForMatchingView(
35669f9658a6e7f2ec1102ffc74bd19d053659cf392Sean Kelley                        allOf(
35769f9658a6e7f2ec1102ffc74bd19d053659cf392Sean Kelley                                withId(R.id.ws_drawer_view_peek_container),
35869f9658a6e7f2ec1102ffc74bd19d053659cf392Sean Kelley                                isCompletelyDisplayed()),
35969f9658a6e7f2ec1102ffc74bd19d053659cf392Sean Kelley                        MAX_WAIT_MS))
36036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(click());
36136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN its click listener should be notified
36236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        verify(mockClickListener).onMenuItemClick(any(MenuItem.class));
36336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
36436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
36536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    @Test
36636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    public void tappingActionDrawerPeekIconShouldTriggerFirstActionAfterItWasOpened() {
36736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // GIVEN a drawer layout with an open action drawer with a title, and mock click listener
36836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        activityRule.launchActivity(
36936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                new DrawerTestActivity.Builder()
37036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
37136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .openBottomDrawerInOnCreate()
37236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .build());
37336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        WearableActionDrawerView actionDrawer =
37436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                (WearableActionDrawerView) activityRule.getActivity()
37536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        .findViewById(R.id.action_drawer);
37636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        OnMenuItemClickListener mockClickListener = mock(OnMenuItemClickListener.class);
37736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        actionDrawer.setOnMenuItemClickListener(mockClickListener);
37836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
37936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // WHEN the action drawer is closed to its peek state and then tapped
38036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        peekDrawer(actionDrawer);
38136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        onView(withId(R.id.action_drawer))
38236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                .perform(waitForMatchingView(allOf(withId(R.id.action_drawer), isPeeking()),
38336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                        MAX_WAIT_MS));
38436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        actionDrawer.getPeekContainer().callOnClick();
38536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
38636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        // THEN its click listener should be notified
38736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        verify(mockClickListener).onMenuItemClick(any(MenuItem.class));
38836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
38936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
39031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    @Test
39131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    public void changingActionDrawerItemShouldUpdateView() {
39231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // GIVEN a drawer layout with an open action drawer
39331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        activityRule.launchActivity(
39431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                new DrawerTestActivity.Builder()
39531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
39631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .openBottomDrawerInOnCreate()
39731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .build());
39831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        WearableActionDrawerView actionDrawer =
39931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                activityRule.getActivity().findViewById(R.id.action_drawer);
40031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final MenuItem secondItem = actionDrawer.getMenu().getItem(1);
40131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
40231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // WHEN its second item is changed
40331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        actionDrawer.post(new Runnable() {
40431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
40531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public void run() {
40631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                secondItem.setTitle("Modified item");
40731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
40831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        });
40931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
41031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // THEN the new item should be displayed
41131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        onView(withText("Modified item")).check(matches(isDisplayed()));
41231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    }
41331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
41431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    @Test
41531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    public void removingActionDrawerItemShouldUpdateView() {
41631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // GIVEN a drawer layout with an open action drawer
41731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        activityRule.launchActivity(
41831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                new DrawerTestActivity.Builder()
41931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
42031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .openBottomDrawerInOnCreate()
42131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .build());
42231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final WearableActionDrawerView actionDrawer =
42331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                activityRule.getActivity().findViewById(R.id.action_drawer);
42431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        MenuItem secondItem = actionDrawer.getMenu().getItem(1);
42531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final int itemId = secondItem.getItemId();
42631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final String title = secondItem.getTitle().toString();
42731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final int initialSize = getChildByType(actionDrawer, RecyclerView.class)
42831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                .getAdapter()
42931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                .getItemCount();
43031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
43131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // WHEN its second item is removed
43231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        actionDrawer.post(new Runnable() {
43331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
43431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public void run() {
43531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                actionDrawer.getMenu().removeItem(itemId);
43631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
43731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        });
43831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
43931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // THEN it should decrease by 1 in size and it should no longer contain the item's text
44031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        onView(allOf(withParent(withId(R.id.action_drawer)), isAssignableFrom(RecyclerView.class)))
44131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                .perform(waitForRecyclerToBeSize(initialSize - 1, MAX_WAIT_MS))
44231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                .perform(waitForMatchingView(recyclerWithoutText(is(title)), MAX_WAIT_MS));
44331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    }
44431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
44531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    @Test
44631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    public void addingActionDrawerItemShouldUpdateView() {
44731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // GIVEN a drawer layout with an open action drawer
44831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        activityRule.launchActivity(
44931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                new DrawerTestActivity.Builder()
45031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
45131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .openBottomDrawerInOnCreate()
45231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .build());
45331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final WearableActionDrawerView actionDrawer =
45431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                activityRule.getActivity().findViewById(R.id.action_drawer);
45531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
45631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        RecyclerView recycler = getChildByType(actionDrawer, RecyclerView.class);
45731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final RecyclerView.LayoutManager layoutManager = recycler.getLayoutManager();
45831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        final int initialSize = recycler.getAdapter().getItemCount();
45931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
46031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // WHEN an item is added and the view is scrolled down (to make sure the view is created)
46131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        actionDrawer.post(new Runnable() {
46231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
46331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public void run() {
46431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                actionDrawer.getMenu().add(0, 42, Menu.NONE, "New Item");
46531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                layoutManager.scrollToPosition(initialSize);
46631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
46731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        });
46831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
46931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        // THEN it should decrease by 1 in size and the there should be a view with the item's text
47031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        onView(allOf(withParent(withId(R.id.action_drawer)), isAssignableFrom(RecyclerView.class)))
47131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                .perform(waitForRecyclerToBeSize(initialSize + 1, MAX_WAIT_MS))
47231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                .perform(waitForMatchingView(withText("New Item"), MAX_WAIT_MS));
47331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    }
47431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
47536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private void scrollToPosition(final RecyclerView recyclerView, final int position) {
47636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        recyclerView.post(new Runnable() {
47736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
47836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            public void run() {
47936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                recyclerView.scrollToPosition(position);
48036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
48136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        });
48236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
48336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
4845c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    private void selectNavItem(final WearableNavigationDrawerView navDrawer, final int index) {
4855c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        navDrawer.post(new Runnable() {
4865c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            @Override
4875c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            public void run() {
4885c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                navDrawer.setCurrentItem(index, false);
4895c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            }
4905c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        });
4915c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    }
4925c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
49336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private void peekDrawer(final WearableDrawerView drawer) {
49436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        drawer.post(new Runnable() {
49536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
49636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            public void run() {
49736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                drawer.getController().peekDrawer();
49836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
49936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        });
50036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
50136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
50236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private void openDrawer(final WearableDrawerView drawer) {
50336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        drawer.post(new Runnable() {
50436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
50536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            public void run() {
50636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                drawer.getController().openDrawer();
50736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
50836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        });
50936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
51036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
5115c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    private static TypeSafeMatcher<View> isOpened(final boolean isOpened) {
5125c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        return new TypeSafeMatcher<View>() {
5135c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            @Override
5145c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            public void describeTo(Description description) {
5155c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                description.appendText("is opened == " + isOpened);
5165c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            }
5175c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
5185c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            @Override
5195c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            public boolean matchesSafely(View view) {
5205c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                return ((WearableDrawerView) view).isOpened() == isOpened;
5215c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            }
5225c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        };
5235c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    }
5245c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
5255c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    private static TypeSafeMatcher<View> isClosed(final boolean isClosed) {
5265c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        return new TypeSafeMatcher<View>() {
5275c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            @Override
5285c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            protected boolean matchesSafely(View view) {
5295c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                WearableDrawerView drawer = (WearableDrawerView) view;
5305c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                return drawer.isClosed() == isClosed;
5315c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            }
5325c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
5335c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            @Override
5345c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            public void describeTo(Description description) {
5355c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley                description.appendText("is closed");
5365c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley            }
5375c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley        };
5385c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley    }
5395c859ba8bcd6f30ec170f61d983379ebd03f4dbcSean Kelley
54036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private TypeSafeMatcher<View> isPeeking() {
54136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        return new TypeSafeMatcher<View>() {
54236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
54336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            protected boolean matchesSafely(View view) {
54436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                WearableDrawerView drawer = (WearableDrawerView) view;
54536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                return drawer.isPeeking();
54636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
54736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
54836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
54936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            public void describeTo(Description description) {
55036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                description.appendText("is peeking");
55136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
55236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        };
55336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
55436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
55536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    private TypeSafeMatcher<View> allowsSwipeToClose() {
55636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        return new TypeSafeMatcher<View>() {
55736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
55836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            protected boolean matchesSafely(View view) {
55936545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                return !view.canScrollHorizontally(-2) && !view.canScrollHorizontally(2);
56036545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
56136545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley
56236545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            @Override
56336545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            public void describeTo(Description description) {
56436545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley                description.appendText("can be swiped closed");
56536545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley            }
56636545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley        };
56736545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley    }
56831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
56931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    /**
57031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * Returns a {@link TypeSafeMatcher} that returns {@code true} when the {@link RecyclerView}
57131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * does not contain a {@link TextView} with text matched by {@code textMatcher}.
57231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     */
57331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    private TypeSafeMatcher<View> recyclerWithoutText(final Matcher<String> textMatcher) {
57431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        return new TypeSafeMatcher<View>() {
57531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
57631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
57731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public void describeTo(Description description) {
57831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                description.appendText("Without recycler text ");
57931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                textMatcher.describeTo(description);
58031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
58131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
58231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
58331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public boolean matchesSafely(View view) {
58431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                if (!(view instanceof RecyclerView)) {
58531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    return false;
58631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                }
58731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
58831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                RecyclerView recycler = ((RecyclerView) view);
58931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                if (recycler.isAnimating()) {
59031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    // While the RecyclerView is animating, it will return null ViewHolders and we
59131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    // won't be able to tell whether the item has been removed or not.
59231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    return false;
59331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                }
59431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
59531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
59631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    RecyclerView.ViewHolder holder = recycler.findViewHolderForAdapterPosition(i);
59731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    if (holder != null) {
59831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        TextView text = getChildByType(holder.itemView, TextView.class);
59931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        if (text != null && textMatcher.matches(text.getText())) {
60031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                            return false;
60131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        }
60231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    }
60331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                }
60431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
60531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                return true;
60631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
60731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        };
60831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    }
60931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
61031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    /**
61131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * Waits for the {@link RecyclerView} to contain {@code targetCount} items, up to {@code millis}
61231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * milliseconds. Throws exception if the time limit is reached before reaching the desired
61331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * number of items.
61431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     */
61531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    public ViewAction waitForRecyclerToBeSize(final int targetCount, final long millis) {
61631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        return new ViewAction() {
61731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
61831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public Matcher<View> getConstraints() {
61931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                return isAssignableFrom(RecyclerView.class);
62031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
62131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
62231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
62331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public String getDescription() {
62431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                return "Waiting for recycler to be size=" + targetCount;
62531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
62631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
62731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            @Override
62831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            public void perform(UiController uiController, View view) {
62931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                if (!(view instanceof RecyclerView)) {
63031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    return;
63131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                }
63231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
63331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                RecyclerView recycler = (RecyclerView) view;
63431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                uiController.loopMainThreadUntilIdle();
63531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                final long startTime = System.currentTimeMillis();
63631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                final long endTime = startTime + millis;
63731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                do {
63831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    if (recycler.getAdapter().getItemCount() == targetCount) {
63931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        return;
64031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    }
64131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                    uiController.loopMainThreadForAtLeast(100); // at least 3 frames
64231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                } while (System.currentTimeMillis() < endTime);
64331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
64431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                // timeout happens
64531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                throw new PerformException.Builder()
64631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .withActionDescription(this.getDescription())
64731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .withViewDescription(HumanReadables.describe(view))
64831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .withCause(new TimeoutException())
64931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                        .build();
65031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
65131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        };
65231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    }
65331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
65431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    /**
65531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * Returns the first child of {@code root} to be an instance of class {@code T}, or {@code null}
65631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     * if none were found.
65731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley     */
65831da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    @Nullable
65931da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    private <T> T getChildByType(View root, Class<T> classOfChildToFind) {
66031da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        for (View child : TreeIterables.breadthFirstViewTraversal(root)) {
66131da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            if (classOfChildToFind.isInstance(child)) {
66231da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley                return (T) child;
66331da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley            }
66431da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        }
66531da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley
66631da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley        return null;
66731da69009a893e97db8c5288b58dc9d84c3a6e85Sean Kelley    }
66836545bb3f2b12af352e550c278cff9026a18ca54Sean Kelley}
669