diff --git a/lib/src/android/support/design/internal/BottomNavigationMenuView.java b/lib/src/android/support/design/internal/BottomNavigationMenuView.java index df361e666..096bdd83a 100644 --- a/lib/src/android/support/design/internal/BottomNavigationMenuView.java +++ b/lib/src/android/support/design/internal/BottomNavigationMenuView.java @@ -86,8 +86,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView { public void onClick(View v) { final BottomNavigationItemView itemView = (BottomNavigationItemView) v; final int itemPosition = itemView.getItemPosition(); - activateNewButton(itemPosition); - mMenu.performItemAction(itemView.getItemData(), mPresenter, 0); + if (!mMenu.performItemAction(itemView.getItemData(), mPresenter, 0)) { + activateNewButton(itemPosition); + } } }; mTempChildWidths = new int[BottomNavigationMenu.MAX_ITEM_COUNT]; diff --git a/lib/src/android/support/design/widget/BottomNavigationView.java b/lib/src/android/support/design/widget/BottomNavigationView.java index e82f1fbad..8a8e0bd05 100644 --- a/lib/src/android/support/design/widget/BottomNavigationView.java +++ b/lib/src/android/support/design/widget/BottomNavigationView.java @@ -152,7 +152,7 @@ public class BottomNavigationView extends FrameLayout { mMenu.setCallback(new MenuBuilder.Callback() { @Override public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - return mListener != null && mListener.onNavigationItemSelected(item); + return mListener != null && !mListener.onNavigationItemSelected(item); } @Override @@ -279,7 +279,9 @@ public class BottomNavigationView extends FrameLayout { * * @param item The selected item * - * @return true to display the item as the selected item + * @return true to display the item as the selected item and false if the item should not + * be selected. Consider setting non-selectable items as disabled preemptively to + * make them appear non-interactive. */ boolean onNavigationItemSelected(@NonNull MenuItem item); } diff --git a/lib/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/lib/tests/src/android/support/design/widget/BottomNavigationViewTest.java index 2c9a2a78e..a14b33ba6 100644 --- a/lib/tests/src/android/support/design/widget/BottomNavigationViewTest.java +++ b/lib/tests/src/android/support/design/widget/BottomNavigationViewTest.java @@ -27,11 +27,15 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.core.AllOf.allOf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import android.content.res.Resources; import android.support.annotation.ColorInt; @@ -95,22 +99,38 @@ public class BottomNavigationViewTest mock(BottomNavigationView.OnNavigationItemSelectedListener.class); mBottomNavigation.setOnNavigationItemSelectedListener(mockedListener); - // Click one of our items + // Make the listener return true to allow selecting the item. + when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(true); onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)), isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click()); - // And that our listener has been notified of the click + // Verify our listener has been notified of the click verify(mockedListener, times(1)).onNavigationItemSelected( mBottomNavigation.getMenu().findItem(R.id.destination_profile)); + // Verify the item is now selected + assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked()); + + // Make the listener return false to disallow selecting the item. + when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(false); + onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)), + isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click()); + // Verify our listener has been notified of the click + verify(mockedListener, times(1)).onNavigationItemSelected( + mBottomNavigation.getMenu().findItem(R.id.destination_people)); + // Verify the previous item is still selected + assertFalse(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked()); + assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked()); // Set null listener to test that the next click is not going to notify the - // previously set listener + // previously set listener and will allow selecting items. mBottomNavigation.setOnNavigationItemSelectedListener(null); // Click one of our items - onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)), + onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)), isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click()); // And that our previous listener has not been notified of the click verifyNoMoreInteractions(mockedListener); + // Verify the correct item is now selected. + assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_home).isChecked()); } @Test