1c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov/*
2c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * Copyright (C) 2016 The Android Open Source Project
3c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov *
4c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * Licensed under the Apache License, Version 2.0 (the "License");
5c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * you may not use this file except in compliance with the License.
6c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * You may obtain a copy of the License at
7c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov *
8c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov *      http://www.apache.org/licenses/LICENSE-2.0
9c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov *
10c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * Unless required by applicable law or agreed to in writing, software
11c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * distributed under the License is distributed on an "AS IS" BASIS,
12c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * See the License for the specific language governing permissions and
14c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov * limitations under the License.
15c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov */
16c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovpackage android.support.design.widget;
17c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
18910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.DrawerLayoutActions.closeDrawer;
19910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.DrawerLayoutActions.openDrawer;
20910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.addHeaderView;
21910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.inflateHeaderView;
22910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.removeHeaderView;
2324e362dd19caffb820011c08125c1a301ba819f8Yuichi Arakiimport static android.support.design.testutils.NavigationViewActions.removeMenuItem;
24910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setCheckedItem;
25910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setIconForMenuItem;
26910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setItemBackground;
27910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setItemBackgroundResource;
28910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setItemIconTintList;
29910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setItemTextAppearance;
30910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.NavigationViewActions.setItemTextColor;
3124e362dd19caffb820011c08125c1a301ba819f8Yuichi Arakiimport static android.support.design.testutils.TestUtilsActions.reinflateMenu;
329a2ea21c22dab29fd8f807052f13091036929c48Yuichi Arakiimport static android.support.design.testutils.TestUtilsActions.restoreHierarchyState;
3324e362dd19caffb820011c08125c1a301ba819f8Yuichi Arakiimport static android.support.design.testutils.TestUtilsMatchers.isActionViewOf;
34910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.TestUtilsMatchers.isChildOfA;
35910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.TestUtilsMatchers.withBackgroundFill;
36910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.TestUtilsMatchers.withStartDrawableFilledWith;
37910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.TestUtilsMatchers.withTextColor;
38910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.design.testutils.TestUtilsMatchers.withTextSize;
39910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.Espresso.onView;
40910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.action.ViewActions.click;
41910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.assertion.ViewAssertions.matches;
42910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.Visibility;
43910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
44910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
459a2ea21c22dab29fd8f807052f13091036929c48Yuichi Arakiimport static android.support.test.espresso.matcher.ViewMatchers.isChecked;
46910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
47910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
48910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
499a2ea21c22dab29fd8f807052f13091036929c48Yuichi Arakiimport static android.support.test.espresso.matcher.ViewMatchers.isNotChecked;
50910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
51910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.withId;
52910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static android.support.test.espresso.matcher.ViewMatchers.withText;
53910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikas
54910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.hamcrest.core.AllOf.allOf;
55910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.junit.Assert.assertEquals;
569c937474b223328601b3c4cb3fa236971c721b2eYuichi Arakiimport static org.junit.Assert.assertFalse;
57910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.junit.Assert.assertNotNull;
58910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.junit.Assert.assertTrue;
59910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.mockito.Mockito.mock;
60910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.mockito.Mockito.times;
61910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.mockito.Mockito.verify;
62910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport static org.mockito.Mockito.verifyNoMoreInteractions;
63910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikas
64c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viveretteimport android.annotation.TargetApi;
65c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovimport android.content.res.Resources;
669c937474b223328601b3c4cb3fa236971c721b2eYuichi Arakiimport android.os.Build;
679a2ea21c22dab29fd8f807052f13091036929c48Yuichi Arakiimport android.os.Parcelable;
688ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikovimport android.support.annotation.ColorInt;
69a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikovimport android.support.annotation.IdRes;
70c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovimport android.support.design.test.R;
71910de28f0a195668fad38ad2367c1f7237a7af98Aurimas Liutikasimport android.support.design.testutils.TestDrawable;
72e6cf359406cd7baaa0659b54c1b7d8ac45db122aAurimas Liutikasimport android.support.test.filters.LargeTest;
7324e362dd19caffb820011c08125c1a301ba819f8Yuichi Arakiimport android.support.test.filters.SdkSuppress;
748ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikovimport android.support.v4.content.res.ResourcesCompat;
75c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovimport android.support.v4.view.GravityCompat;
76c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovimport android.support.v4.widget.DrawerLayout;
778ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikovimport android.support.v7.widget.RecyclerView;
781ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikovimport android.support.v7.widget.SwitchCompat;
799a2ea21c22dab29fd8f807052f13091036929c48Yuichi Arakiimport android.util.SparseArray;
80a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikovimport android.view.LayoutInflater;
81a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikovimport android.view.Menu;
82a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikovimport android.view.MenuItem;
83a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikovimport android.view.View;
84f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Arakiimport android.widget.TextView;
85f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki
868ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikovimport org.hamcrest.Matcher;
87c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovimport org.junit.Before;
88c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovimport org.junit.Test;
89c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
908ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikovimport java.util.HashMap;
918ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikovimport java.util.Map;
928ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
93e6cf359406cd7baaa0659b54c1b7d8ac45db122aAurimas Liutikas@LargeTest
94c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikovpublic class NavigationViewTest
95c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        extends BaseInstrumentationTestCase<NavigationViewActivity> {
968ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    private static final int[] MENU_CONTENT_ITEM_IDS = { R.id.destination_home,
978ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            R.id.destination_profile, R.id.destination_people, R.id.destination_settings };
988ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    private Map<Integer, String> mMenuStringContent;
998ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
100c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    private DrawerLayout mDrawerLayout;
101c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
102f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu    private NavigationTestView mNavigationView;
103c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
104c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    public NavigationViewTest() {
105c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        super(NavigationViewActivity.class);
106c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    }
107c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
108c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    @Before
109c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    public void setUp() throws Exception {
110c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        final NavigationViewActivity activity = mActivityTestRule.getActivity();
111c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        mDrawerLayout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
112f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu        mNavigationView = (NavigationTestView) mDrawerLayout.findViewById(R.id.start_drawer);
113c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
114c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        // Close the drawer to reset the state for the next test
115c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(closeDrawer(GravityCompat.START));
1168ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
1178ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final Resources res = activity.getResources();
1188ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        mMenuStringContent = new HashMap<>(MENU_CONTENT_ITEM_IDS.length);
1198ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        mMenuStringContent.put(R.id.destination_home, res.getString(R.string.navigate_home));
1208ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        mMenuStringContent.put(R.id.destination_profile, res.getString(R.string.navigate_profile));
1218ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
1228ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        mMenuStringContent.put(R.id.destination_settings,
1238ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                res.getString(R.string.navigate_settings));
124c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    }
125c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
126c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    @Test
127c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    public void testBasics() {
128c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        // Open our drawer
129c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
130c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
131a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Check the contents of the Menu object
132a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final Menu menu = mNavigationView.getMenu();
133a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        assertNotNull("Menu should not be null", menu);
134f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki        assertEquals("Should have matching number of items", MENU_CONTENT_ITEM_IDS.length + 1,
135a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                menu.size());
136a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
137a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            final MenuItem currItem = menu.getItem(i);
138a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            assertEquals("ID for Item #" + i, MENU_CONTENT_ITEM_IDS[i], currItem.getItemId());
139a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        }
140a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
1418ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Check that we have the expected menu items in our NavigationView
1428ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
1438ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
1448ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)))).check(matches(isDisplayed()));
1458ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
1468ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    }
1478ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
1488ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    @Test
1499c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki    public void testWillNotDraw() {
1509c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki        // Open our drawer
1519c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
1529c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki
1539c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki        if (Build.VERSION.SDK_INT >= 21) {
154f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu            if (mNavigationView.hasSystemWindowInsets()) {
155f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu                assertFalse(mNavigationView.willNotDraw());
156f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu            } else {
157f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu                assertTrue(mNavigationView.willNotDraw());
158f16fff9d2dc208f57e8d5d29da986e3e563da9a8Dake Gu            }
1599c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki        } else {
1609c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki            assertTrue(mNavigationView.willNotDraw());
1619c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki        }
1629c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki    }
1639c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki
1649c937474b223328601b3c4cb3fa236971c721b2eYuichi Araki    @Test
1658ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    public void testTextAppearance() {
1668ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Open our drawer
1678ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
1688ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
169c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov        final Resources res = mActivityTestRule.getActivity().getResources();
1708ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final int defaultTextSize = res.getDimensionPixelSize(R.dimen.text_medium_size);
171c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov
1728ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Check the default style of the menu items in our NavigationView
1738ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
1748ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
1758ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)))).check(
1768ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    matches(withTextSize(defaultTextSize)));
1778ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
1788ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
1798ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Set a new text appearance on our NavigationView
1808ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemTextAppearance(R.style.TextSmallStyle));
1818ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
1828ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // And check that all the menu items have the new style
1838ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final int newTextSize = res.getDimensionPixelSize(R.dimen.text_small_size);
1848ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
1858ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
1868ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)))).check(
1878ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    matches(withTextSize(newTextSize)));
1888ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
1898ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    }
1908ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
1918ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    @Test
1928ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    public void testTextColor() {
1938ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Open our drawer
1948ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
1958ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
1968ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final Resources res = mActivityTestRule.getActivity().getResources();
1978ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int defaultTextColor = ResourcesCompat.getColor(res,
1988ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.emerald_text, null);
1998ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2008ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Check the default text color of the menu items in our NavigationView
2018ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
2028ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
2038ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)))).check(
2048ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    matches(withTextColor(defaultTextColor)));
2058ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
2068ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2078ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Set a new text color on our NavigationView
2088ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemTextColor(
2098ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                ResourcesCompat.getColorStateList(res, R.color.color_state_list_lilac, null)));
2108ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2118ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // And check that all the menu items have the new color
2128ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int newTextColor = ResourcesCompat.getColor(res,
2138ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.lilac_default, null);
2148ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
2158ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
2168ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)))).check(
2178ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    matches(withTextColor(newTextColor)));
2188ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
2198ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    }
2208ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2218ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    @Test
2228ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    public void testBackground() {
2238ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Open our drawer
2248ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
2258ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2268ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final Resources res = mActivityTestRule.getActivity().getResources();
2278ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int defaultFillColor = ResourcesCompat.getColor(res,
2288ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.sand_default, null);
2298ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2308ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Check the default fill color of the menu items in our NavigationView
2318ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
2328ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            // Note that here we're tying ourselves to the implementation details of the
2338ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            // internal structure of the NavigationView. Specifically, we're looking at the
2348ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            // direct child of RecyclerView which is expected to have the background set
2358ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            // on it. If the internal implementation of NavigationView changes, the second
2368ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            // Matcher below will need to be tweaked.
2378ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            Matcher menuItemMatcher = allOf(
2388ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
2398ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isChildOfA(isAssignableFrom(RecyclerView.class)),
2408ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)));
2418ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2428ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(menuItemMatcher).check(matches(withBackgroundFill(defaultFillColor)));
2438ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
2448ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2458ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Set a new background (flat fill color) on our NavigationView
2468ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemBackgroundResource(
2478ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.drawable.test_background_blue));
2488ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2498ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // And check that all the menu items have the new fill
2508ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int newFillColorBlue = ResourcesCompat.getColor(res,
2518ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.test_blue, null);
2528ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
2538ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            Matcher menuItemMatcher = allOf(
2548ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
2558ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isChildOfA(isAssignableFrom(RecyclerView.class)),
2568ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)));
2578ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2588ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(menuItemMatcher).check(matches(withBackgroundFill(newFillColorBlue)));
2598ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
2608ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2618ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Set another new background on our NavigationView
2628ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemBackground(
2638ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                ResourcesCompat.getDrawable(res, R.drawable.test_background_green, null)));
2648ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2658ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // And check that all the menu items have the new fill
2668ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int newFillColorGreen = ResourcesCompat.getColor(res,
2678ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.test_green, null);
2688ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
2698ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            Matcher menuItemMatcher = allOf(
2708ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
2718ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isChildOfA(isAssignableFrom(RecyclerView.class)),
2728ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)));
2738ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2748ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov            onView(menuItemMatcher).check(matches(withBackgroundFill(newFillColorGreen)));
2758ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        }
2768ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    }
2778ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2788ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    @Test
2798ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov    public void testIconTinting() {
2808ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Open our drawer
2818ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
2828ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2838ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final Resources res = mActivityTestRule.getActivity().getResources();
28488f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        final @ColorInt int redFill = ResourcesCompat.getColor(res, R.color.test_red, null);
28588f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        final @ColorInt int greenFill = ResourcesCompat.getColor(res, R.color.test_green, null);
28688f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        final @ColorInt int blueFill = ResourcesCompat.getColor(res, R.color.test_blue, null);
28788f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        final int iconSize = res.getDimensionPixelSize(R.dimen.drawable_small_size);
28888f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setIconForMenuItem(R.id.destination_home,
28988f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov                new TestDrawable(redFill, iconSize, iconSize)));
29088f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setIconForMenuItem(R.id.destination_profile,
29188f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov                new TestDrawable(greenFill, iconSize, iconSize)));
29288f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setIconForMenuItem(R.id.destination_people,
29388f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov                new TestDrawable(blueFill, iconSize, iconSize)));
29488f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov
2958ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int defaultTintColor = ResourcesCompat.getColor(res,
2968ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.emerald_translucent, null);
2978ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
2988ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // We're allowing a margin of error in checking the color of the items' icons.
2998ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // This is due to the translucent color being used in the icon tinting
3008ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // and off-by-one discrepancies of SRC_IN when it's compositing
3018ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // translucent color. Note that all the checks below are written for the current
3028ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // logic on NavigationView that uses the default SRC_IN tint mode - effectively
3038ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // replacing all non-transparent pixels in the destination (original icon) with
3048ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // our translucent tint color.
3058ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final int allowedComponentVariance = 1;
3068ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
3078ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Note that here we're tying ourselves to the implementation details of the
3088ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // internal structure of the NavigationView. Specifically, we're checking the
3098ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // start drawable of the text view with the specific text. If the internal
3108ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // implementation of NavigationView changes, the second Matcher in the lookups
3118ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // below will need to be tweaked.
3128ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
3138ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
3148ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
3158ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
3168ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
3178ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
3188ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
3198ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
3208ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
3218ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
3228ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        final @ColorInt int newTintColor = ResourcesCompat.getColor(res,
3238ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                R.color.red_translucent, null);
3248ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
3258ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemIconTintList(
3268ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                ResourcesCompat.getColorStateList(res, R.color.color_state_list_red_translucent,
3278ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                        null)));
3288ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Check that all menu items with icons now have icons tinted with the newly set color
3298ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
3308ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
3318ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
3328ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
3338ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
3348ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
3358ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
3368ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
3378ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                    withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
3388ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov
3398ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // And now remove all icon tinting
3408ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemIconTintList(null));
3418ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // And verify that all menu items with icons now have the original colors for their icons.
3428ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // Note that since there is no tinting at this point, we don't allow any color variance
3438ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        // in these checks.
3448ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
3458ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
34688f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov                    withStartDrawableFilledWith(redFill, 0)));
3478ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
3488ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
34988f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov                    withStartDrawableFilledWith(greenFill, 0)));
3508ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
3518ea47e618ba5dad21c7b023aa998979eebcf2103Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
35288f685bc75d52b18f45f22c99ef8d4910708a3e3Kirill Grouchnikov                    withStartDrawableFilledWith(blueFill, 0)));
353c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov    }
354a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
355a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    /**
356a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov     * Gets the list of header IDs (which can be empty) and verifies that the actual header content
357a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov     * of our navigation view matches the expected header content.
358a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov     */
359a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    private void verifyHeaders(@IdRes int ... expectedHeaderIds) {
360a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final int expectedHeaderCount = (expectedHeaderIds != null) ? expectedHeaderIds.length : 0;
361a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final int actualHeaderCount = mNavigationView.getHeaderCount();
362a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        assertEquals("Header count", expectedHeaderCount, actualHeaderCount);
363a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
364a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        if (expectedHeaderCount > 0) {
365a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            for (int i = 0; i < expectedHeaderCount; i++) {
366a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                final View currentHeader = mNavigationView.getHeaderView(i);
367a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                assertEquals("Header at #" + i, expectedHeaderIds[i], currentHeader.getId());
368a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            }
369a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        }
370a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    }
371a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
372a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    @Test
373a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    public void testHeaders() {
374a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Open our drawer
375a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
376a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
377a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // We should have no headers at the start
378a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyHeaders();
379a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
380a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Inflate one header and check that it's there in the navigation view
381a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(
382a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                inflateHeaderView(R.layout.design_navigation_view_header1));
383a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyHeaders(R.id.header1);
384a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
385a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
386a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
387a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Add one more header and check that it's there in the navigation view
388a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(
389a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                addHeaderView(inflater, R.layout.design_navigation_view_header2));
390a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyHeaders(R.id.header1, R.id.header2);
391a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
392a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final View header1 = mNavigationView.findViewById(R.id.header1);
393a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Remove the first header and check that we still have the second header
394a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(removeHeaderView(header1));
395a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyHeaders(R.id.header2);
396a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
397a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Add one more header and check that we now have two headers
398a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(
399a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                inflateHeaderView(R.layout.design_navigation_view_header3));
400a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyHeaders(R.id.header2, R.id.header3);
401a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
402a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Add another "copy" of the header from the just-added layout and check that we now
403a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // have three headers
404a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(
405a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                addHeaderView(inflater, R.layout.design_navigation_view_header3));
406a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyHeaders(R.id.header2, R.id.header3, R.id.header3);
407a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    }
408a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
40924e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki    @SdkSuppress(minSdkVersion = 11)
410c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette    @TargetApi(11)
411a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    @Test
4129a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki    public void testHeaderState() {
4139a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Open our drawer
4149a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
4159a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4169a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Inflate a header with a toggle switch and check that it's there in the navigation view
4179a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.start_drawer)).perform(
4189a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                inflateHeaderView(R.layout.design_navigation_view_header_switch));
4199a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        verifyHeaders(R.id.header_frame);
4209a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4219a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.header_toggle))
4229a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                .check(matches(isNotChecked()))
4239a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                .perform(click())
4249a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                .check(matches(isChecked()));
4259a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4269a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Save the current state
4279a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        SparseArray<Parcelable> container = new SparseArray<>();
4289a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        mNavigationView.saveHierarchyState(container);
4299a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4309a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Remove the header
4319a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        final View header = mNavigationView.findViewById(R.id.header_frame);
4329a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.start_drawer)).perform(removeHeaderView(header));
4339a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        verifyHeaders();
4349a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4359a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Inflate the header again
4369a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.start_drawer)).perform(
4379a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                inflateHeaderView(R.layout.design_navigation_view_header_switch));
4389a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        verifyHeaders(R.id.header_frame);
4399a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4409a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Restore the saved state
4419a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.start_drawer)).perform(
4429a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                restoreHierarchyState(container));
4439a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
4449a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        // Confirm that the state was restored
4459a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki        onView(withId(R.id.header_toggle))
4469a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki                .check(matches(isChecked()));
4479a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki    }
4489a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki
44924e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki    @SdkSuppress(minSdkVersion = 11)
450c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette    @TargetApi(11)
45124e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki    @Test
45224e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki    public void testActionViewState() {
45324e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        // Open our drawer
45424e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
45524e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki
45624e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        final Menu menu = mNavigationView.getMenu();
45724e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        onView(isActionViewOf(menu, R.id.destination_people))
45824e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .check(matches(isNotChecked())) // Not checked by default
45924e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .perform(click())               // Check it
46024e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .check(matches(isChecked()));
46124e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki
46224e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        // Remove the other action view to simulate the case where it is not yet inflated
46324e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        onView(isActionViewOf(menu, R.id.destination_custom))
46424e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .check(matches(isDisplayed()));
46524e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        onView(withId(R.id.start_drawer))
46624e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .perform(removeMenuItem(R.id.destination_custom));
46724e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki
46824e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        // Save the current state
46924e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        SparseArray<Parcelable> container = new SparseArray<>();
47024e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        mNavigationView.saveHierarchyState(container);
47124e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki
47224e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        // Restore the saved state
47324e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        onView(withId(R.id.start_drawer))
47424e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .perform(reinflateMenu(R.menu.navigation_view_content))
47524e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .perform(restoreHierarchyState(container));
47624e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki
47724e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        // Checked state should be restored
47824e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki        onView(isActionViewOf(menu, R.id.destination_people))
47924e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki                .check(matches(isChecked()));
48024e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki    }
48124e362dd19caffb820011c08125c1a301ba819f8Yuichi Araki
4829a2ea21c22dab29fd8f807052f13091036929c48Yuichi Araki    @Test
483a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    public void testNavigationSelectionListener() {
484a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Open our drawer
485a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
486a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
487a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Click one of our items
488a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
489a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
490a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Check that the drawer is still open
491a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        assertTrue("Drawer is still open after click",
492a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                mDrawerLayout.isDrawerOpen(GravityCompat.START));
493a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
494a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Register a listener
4958cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov        NavigationView.OnNavigationItemSelectedListener mockedListener =
4968cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov                mock(NavigationView.OnNavigationItemSelectedListener.class);
4978cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov        mNavigationView.setNavigationItemSelectedListener(mockedListener);
498a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
499a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Click one of our items
500a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
501a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
502a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Check that the drawer is still open
503a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        assertTrue("Drawer is still open after click",
504a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                mDrawerLayout.isDrawerOpen(GravityCompat.START));
505a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // And that our listener has been notified of the click
5068cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov        verify(mockedListener, times(1)).onNavigationItemSelected(
5078cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov                mNavigationView.getMenu().findItem(R.id.destination_profile));
508a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
5098cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov        // Set null listener to test that the next click is not going to notify the
5108cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov        // previously set listener
511a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        mNavigationView.setNavigationItemSelectedListener(null);
512a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
513a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Click one of our items
514a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_settings)),
515a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
516a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Check that the drawer is still open
517a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        assertTrue("Drawer is still open after click",
518a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                mDrawerLayout.isDrawerOpen(GravityCompat.START));
519a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // And that our previous listener has not been notified of the click
5208cf1dce2d2266ea5b1d42e95af81490d4d201802Kirill Grouchnikov        verifyNoMoreInteractions(mockedListener);
521a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    }
522a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
523a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    private void verifyCheckedAppearance(@IdRes int checkedItemId,
524a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            @ColorInt int uncheckedItemForeground, @ColorInt int checkedItemForeground,
525a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            @ColorInt int uncheckedItemBackground, @ColorInt int checkedItemBackground) {
526a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
527a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            final boolean expectedToBeChecked = (MENU_CONTENT_ITEM_IDS[i] == checkedItemId);
528a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            final @ColorInt int expectedItemForeground =
529a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    expectedToBeChecked ? checkedItemForeground : uncheckedItemForeground;
530a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            final @ColorInt int expectedItemBackground =
531a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    expectedToBeChecked ? checkedItemBackground : uncheckedItemBackground;
532a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
533a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            // For the background fill check we need to select a view that has its background
534a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            // set by the current implementation (see disclaimer in testBackground)
535a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            Matcher menuItemMatcher = allOf(
536a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
537a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    isChildOfA(isAssignableFrom(RecyclerView.class)),
538a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)));
539a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            onView(menuItemMatcher).check(matches(withBackgroundFill(expectedItemBackground)));
540a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
541a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            // And for the foreground color check we need to select a view with the text content
542a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            Matcher menuItemTextMatcher = allOf(
543a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
544a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    isDescendantOfA(withId(R.id.start_drawer)));
545a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov            onView(menuItemTextMatcher).check(matches(withTextColor(expectedItemForeground)));
546a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        }
547a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    }
548a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
549a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    @Test
550a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    public void testCheckedAppearance() {
551a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Open our drawer
552a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
553a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
554a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Reconfigure our navigation view to use foreground (text) and background visuals
555a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // with explicitly different colors for the checked state
556a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final Resources res = mActivityTestRule.getActivity().getResources();
557a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemTextColor(
558a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                ResourcesCompat.getColorStateList(res, R.color.color_state_list_sand, null)));
559a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setItemBackgroundResource(
560a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                R.drawable.test_drawable_state_list));
561a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
562a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final @ColorInt int uncheckedItemForeground = ResourcesCompat.getColor(res,
563a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                R.color.sand_default, null);
564a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final @ColorInt int checkedItemForeground = ResourcesCompat.getColor(res,
565a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                R.color.sand_checked, null);
566a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final @ColorInt int uncheckedItemBackground = ResourcesCompat.getColor(res,
567a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                R.color.test_green, null);
568a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        final @ColorInt int checkedItemBackground = ResourcesCompat.getColor(res,
569a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                R.color.test_blue, null);
570a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
571a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Verify that all items are rendered with unchecked visuals
572a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyCheckedAppearance(0, uncheckedItemForeground, checkedItemForeground,
573a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemBackground, checkedItemBackground);
574a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
575a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Mark one of the items as checked
576a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(withId(R.id.start_drawer)).perform(setCheckedItem(R.id.destination_profile));
577a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // And verify that it's now rendered with checked visuals
578a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyCheckedAppearance(R.id.destination_profile,
579a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemForeground, checkedItemForeground,
580a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemBackground, checkedItemBackground);
581a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
582a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Register a navigation listener that "marks" the selected item
583a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        mNavigationView.setNavigationItemSelectedListener(
584a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                new NavigationView.OnNavigationItemSelectedListener() {
585a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    @Override
586a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    public boolean onNavigationItemSelected(MenuItem item) {
587a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                        return true;
588a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    }
589a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                });
590a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
591a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Click one of our items
592a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
593a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
594a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // and verify that it's now checked
595a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyCheckedAppearance(R.id.destination_people,
596a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemForeground, checkedItemForeground,
597a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemBackground, checkedItemBackground);
598a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
599a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Register a navigation listener that doesn't "mark" the selected item
600a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        mNavigationView.setNavigationItemSelectedListener(
601a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                new NavigationView.OnNavigationItemSelectedListener() {
602a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    @Override
603a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    public boolean onNavigationItemSelected(MenuItem item) {
604a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                        return false;
605a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                    }
606a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                });
607a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov
608a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // Click another items
609a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        onView(allOf(withText(mMenuStringContent.get(R.id.destination_settings)),
610a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
611a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // and verify that the checked state remains on the previously clicked item
612a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // since the current navigation listener returns false from its callback
613a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        // implementation
614a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov        verifyCheckedAppearance(R.id.destination_people,
615a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemForeground, checkedItemForeground,
616a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov                uncheckedItemBackground, checkedItemBackground);
617a3c0da0361aa877077aeb21df876226def2f98caKirill Grouchnikov    }
6181ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov
6191ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov    @Test
6201ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov    public void testActionLayout() {
6211ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // Open our drawer
6221ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
6231ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov
6241ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // There are four conditions to "find" the menu item with action layout (switch):
6251ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // 1. Is in the NavigationView
6261ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // 2. Is direct child of a class that extends RecyclerView
6271ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // 3. Has a child with "people" text
6281ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // 4. Has fully displayed child that extends SwitchCompat
6291ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // Note that condition 2 makes a certain assumption about the internal implementation
6301ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // details of the NavigationMenu, while conditions 3 and 4 aim to be as generic as
6311ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // possible and to not rely on the internal details of the current layout implementation
6321ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // of an individual menu item in NavigationMenu.
6331ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        Matcher menuItemMatcher = allOf(
6341ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov                isDescendantOfA(withId(R.id.start_drawer)),
6351ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov                isChildOfA(isAssignableFrom(RecyclerView.class)),
6361ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov                hasDescendant(withText(mMenuStringContent.get(R.id.destination_people))),
6371ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov                hasDescendant(allOf(
6381ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov                        isAssignableFrom(SwitchCompat.class),
6391ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov                        isCompletelyDisplayed())));
6401ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov
6411ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // While we don't need to perform any action on our row, the invocation of perform()
6421ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // makes our matcher actually run. If for some reason NavigationView fails to inflate and
6431ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        // display our SwitchCompat action layout, the next line will fail in the matcher pass.
6441ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov        onView(menuItemMatcher).perform(click());
645f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki
646f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki        // Check that the full custom view is displayed without title and icon.
647f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki        final Resources res = mActivityTestRule.getActivity().getResources();
648f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki        Matcher customItemMatcher = allOf(
649f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki                isDescendantOfA(withId(R.id.start_drawer)),
650f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki                isChildOfA(isAssignableFrom(RecyclerView.class)),
651f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki                hasDescendant(withText(res.getString(R.string.navigate_custom))),
652f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki                hasDescendant(allOf(
653f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki                        isAssignableFrom(TextView.class),
654f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki                        withEffectiveVisibility(Visibility.GONE))));
655f3865fbd67715b07d43da357dea742edf3bf9913Yuichi Araki        onView(customItemMatcher).perform(click());
6561ba555a31dcff069a4b9beb4d552203fab2d2691Kirill Grouchnikov    }
657c10ba2544591704e7c4adbe98da6a485a8b19230Kirill Grouchnikov}
658