Change Nav testapp's top level based on screen size
Update the Navigation testapp to adapt the top level
navigation pattern based on the available screen size:
- On very small screens (such as is common on phones
with multi-window or phones in landscape), use a
navigation drawer to keep navigation out of the way
but accessible
- When there is enough height (such as normal devices in
portrait), use bottom navigation
- On larger tablets in landscape and Chromebooks, use a
persistent navigation drawer that is always visible to
better use the available space
Test: testapp runs, works on multi-window on phones through Pixel C
BUG: 37573313
Change-Id: Ib78090be4ecc0cd7c7c9eb5010f098b51a8d6c57
diff --git a/navigation/integration-tests/testapp/src/main/AndroidManifest.xml b/navigation/integration-tests/testapp/src/main/AndroidManifest.xml
index 26ee9da..127a240 100644
--- a/navigation/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/navigation/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -21,16 +21,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon">
- <activity android:name="com.android.support.navigation.testapp.DrawerActivity"
- android:label="@string/drawer_navigation">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="com.android.support.navigation.testapp.BottomNavActivity"
- android:label="@string/bottom_navigation">
+ <activity android:name="com.android.support.navigation.testapp.NavigationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
diff --git a/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/BottomNavActivity.java b/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/BottomNavActivity.java
deleted file mode 100644
index c1f060d..0000000
--- a/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/BottomNavActivity.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.support.navigation.testapp;
-
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.design.widget.BottomNavigationView;
-import android.support.navigation.app.nav.NavController;
-import android.support.navigation.app.nav.NavDestination;
-import android.support.navigation.app.nav.NavHostFragment;
-import android.support.navigation.app.nav.Navigation;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.Toast;
-
-/**
- * A simple activity demonstrating use of a NavHostFragment with a bottom navigation bar.
- */
-public class BottomNavActivity extends AppCompatActivity {
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.bottom_nav_activity);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- NavHostFragment host = (NavHostFragment) getSupportFragmentManager()
- .findFragmentById(R.id.my_nav_host_fragment);
-
- if (host != null) {
- NavController navController = host.getNavController();
- NavHelper.setupActionBar(navController, this);
- BottomNavigationView bottomNavView =
- (BottomNavigationView) findViewById(R.id.bottom_nav_view);
- NavHelper.setupBottomNavigationView(navController, bottomNavView);
- navController.addOnNavigatedListener(new NavController.OnNavigatedListener() {
- @Override
- public void onNavigated(NavController controller, NavDestination destination) {
- String dest = getResources().getResourceName(destination.getId());
- Toast.makeText(BottomNavActivity.this, "Navigated to "
- + dest,
- Toast.LENGTH_SHORT).show();
- Log.d("BottomNavActivity", "Navigated to " + dest, new Throwable());
- }
- });
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- NavController navController = Navigation.findController(this, R.id.my_nav_host_fragment);
- NavHelper.addChildDestinationsToMenu(navController.getGraph(), menu,
- NavDestination.NAV_TYPE_SECONDARY);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- return NavHelper.handleMenuItemSelected(
- Navigation.findController(this, R.id.my_nav_host_fragment), item)
- || super.onOptionsItemSelected(item);
- }
-}
diff --git a/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavHelper.java b/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavHelper.java
index a920dd1..7fb9584 100644
--- a/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavHelper.java
+++ b/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavHelper.java
@@ -213,22 +213,8 @@
*/
public static void setupActionBar(final NavController navController,
final AppCompatActivity activity, final DrawerLayout drawerLayout) {
- ActionBar actionBar = activity.getSupportActionBar();
- NavDestination currentDestination = navController.getCurrentDestination();
- if (currentDestination != null && !TextUtils.isEmpty(currentDestination.getLabel())) {
- actionBar.setTitle(currentDestination.getLabel());
- }
- ActionBarOnNavigatedListener actionBarOnNavigatedListener =
- new ActionBarOnNavigatedListener(activity, drawerLayout);
- navController.addOnNavigatedListener(actionBarOnNavigatedListener);
- boolean isStartDestination = currentDestination == null
- || currentDestination.getId() == navController.getGraph().getStartDestination();
- actionBar.setDisplayHomeAsUpEnabled(drawerLayout != null || !isStartDestination);
- // Set the initial state of the up indicator: it should show as the drawer indicator
- // if there is a DrawerLayout and we're on the starting destination, otherwise it should
- // show as an Up arrow.
- actionBarOnNavigatedListener.setActionBarUpIndicator(
- drawerLayout != null && isStartDestination, false);
+ navController.addOnNavigatedListener(
+ new ActionBarOnNavigatedListener(activity, drawerLayout));
}
/**
@@ -266,6 +252,9 @@
public static void setupNavigationView(final NavController navController,
final NavigationView navigationView,
final NavigationView.OnNavigationItemSelectedListener listener) {
+ if (navigationView == null) {
+ return;
+ }
addChildDestinationsToMenu(navController.getGraph(), navigationView.getMenu(),
NavDestination.NAV_TYPE_PRIMARY | NavDestination.NAV_TYPE_SECONDARY);
navigationView.setNavigationItemSelectedListener(
@@ -330,6 +319,9 @@
public static void setupBottomNavigationView(final NavController navController,
final BottomNavigationView bottomNavigationView,
final BottomNavigationView.OnNavigationItemSelectedListener listener) {
+ if (bottomNavigationView == null) {
+ return;
+ }
addChildDestinationsToMenu(navController.getGraph(), bottomNavigationView.getMenu(),
NavDestination.NAV_TYPE_PRIMARY);
bottomNavigationView.setOnNavigationItemSelectedListener(
@@ -381,15 +373,18 @@
boolean isStartDestination =
controller.getGraph().getStartDestination() == destination.getId();
actionBar.setDisplayHomeAsUpEnabled(mDrawerLayout != null || !isStartDestination);
- setActionBarUpIndicator(mDrawerLayout != null && isStartDestination, true);
+ setActionBarUpIndicator(mDrawerLayout != null && isStartDestination);
}
- void setActionBarUpIndicator(boolean showAsDrawerIndicator, boolean animate) {
+ void setActionBarUpIndicator(boolean showAsDrawerIndicator) {
ActionBarDrawerToggle.Delegate delegate = mActivity.getDrawerToggleDelegate();
+ boolean animate = true;
if (mArrowDrawable == null) {
mArrowDrawable = new DrawerArrowDrawable(
delegate.getActionBarThemedContext());
delegate.setActionBarUpIndicator(mArrowDrawable, 0);
+ // We're setting the initial state, so skip the animation
+ animate = false;
}
float endValue = showAsDrawerIndicator ? 0f : 1f;
if (animate) {
diff --git a/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/DrawerActivity.java b/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavigationActivity.java
similarity index 69%
rename from navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/DrawerActivity.java
rename to navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavigationActivity.java
index c4d2f4a..0505325 100644
--- a/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/DrawerActivity.java
+++ b/navigation/integration-tests/testapp/src/main/java/com/android/support/navigation/testapp/NavigationActivity.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.NavigationView;
import android.support.navigation.app.nav.NavController;
import android.support.navigation.app.nav.NavDestination;
@@ -27,19 +28,20 @@
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
+import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
/**
* A simple activity demonstrating use of a NavHostFragment with a navigation drawer.
*/
-public class DrawerActivity extends AppCompatActivity {
+public class NavigationActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.drawer_activity);
+ setContentView(R.layout.navigation_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
@@ -53,20 +55,39 @@
NavHelper.setupActionBar(navController, this, mDrawerLayout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
NavHelper.setupNavigationView(navController, navigationView);
+ BottomNavigationView bottomNavView =
+ (BottomNavigationView) findViewById(R.id.bottom_nav_view);
+ NavHelper.setupBottomNavigationView(navController, bottomNavView);
navController.addOnNavigatedListener(new NavController.OnNavigatedListener() {
@Override
public void onNavigated(NavController controller, NavDestination destination) {
String dest = getResources().getResourceName(destination.getId());
- Toast.makeText(DrawerActivity.this, "Navigated to "
+ Toast.makeText(NavigationActivity.this, "Navigated to "
+ dest,
Toast.LENGTH_SHORT).show();
- Log.d("DrawerActivity", "Navigated to " + dest, new Throwable());
+ Log.d("NavigationActivity", "Navigated to " + dest, new Throwable());
}
});
}
}
@Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ boolean retValue = super.onCreateOptionsMenu(menu);
+ BottomNavigationView bottomNavView =
+ (BottomNavigationView) findViewById(R.id.bottom_nav_view);
+ // Only add secondary navigation elements to the menu if there is a BottomNavigationView
+ if (bottomNavView != null) {
+ NavController navController =
+ Navigation.findController(this, R.id.my_nav_host_fragment);
+ NavHelper.addChildDestinationsToMenu(navController.getGraph(), menu,
+ NavDestination.NAV_TYPE_SECONDARY);
+ return true;
+ }
+ return retValue;
+ }
+
+ @Override
public boolean onOptionsItemSelected(MenuItem item) {
return NavHelper.handleMenuItemSelected(
Navigation.findController(this, R.id.my_nav_host_fragment), item, mDrawerLayout)
diff --git a/navigation/integration-tests/testapp/src/main/res/layout/bottom_nav_activity.xml b/navigation/integration-tests/testapp/src/main/res/layout-h470dp/navigation_activity.xml
similarity index 98%
rename from navigation/integration-tests/testapp/src/main/res/layout/bottom_nav_activity.xml
rename to navigation/integration-tests/testapp/src/main/res/layout-h470dp/navigation_activity.xml
index 9bb1441..54eecb0 100644
--- a/navigation/integration-tests/testapp/src/main/res/layout/bottom_nav_activity.xml
+++ b/navigation/integration-tests/testapp/src/main/res/layout-h470dp/navigation_activity.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 The Android Open Source Project
+ ~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
+ ~
~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/navigation/integration-tests/testapp/src/main/res/layout-w960dp/navigation_activity.xml b/navigation/integration-tests/testapp/src/main/res/layout-w960dp/navigation_activity.xml
new file mode 100644
index 0000000..203889a
--- /dev/null
+++ b/navigation/integration-tests/testapp/src/main/res/layout-w960dp/navigation_activity.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <android.support.design.widget.NavigationView
+ android:id="@+id/nav_view"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ app:elevation="0dp"
+ app:headerLayout="@layout/nav_view_header"/>
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/nav_view"
+ android:layout_toEndOf="@id/nav_view"
+ android:background="?android:attr/listDivider"/>
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/colorPrimary"
+ android:theme="@style/ThemeOverlay.AppCompat.Dark"
+ android:layout_toRightOf="@id/nav_view"
+ android:layout_toEndOf="@id/nav_view"
+ android:layout_alignParentTop="true"/>
+ <fragment
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/my_nav_host_fragment"
+ android:name="android.support.navigation.app.nav.NavHostFragment"
+ app:navGraph="@xml/nav_main"
+ app:defaultNavHost="true"
+ android:layout_toRightOf="@id/nav_view"
+ android:layout_toEndOf="@id/nav_view"
+ android:layout_below="@id/toolbar"/>
+</RelativeLayout>
diff --git a/navigation/integration-tests/testapp/src/main/res/layout/main_fragment.xml b/navigation/integration-tests/testapp/src/main/res/layout/main_fragment.xml
index e7f7060..9f797c9 100644
--- a/navigation/integration-tests/testapp/src/main/res/layout/main_fragment.xml
+++ b/navigation/integration-tests/testapp/src/main/res/layout/main_fragment.xml
@@ -13,7 +13,8 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:padding="8dp">
<TextView android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/navigation/integration-tests/testapp/src/main/res/layout/nav_view_header.xml b/navigation/integration-tests/testapp/src/main/res/layout/nav_view_header.xml
new file mode 100644
index 0000000..d7be09f
--- /dev/null
+++ b/navigation/integration-tests/testapp/src/main/res/layout/nav_view_header.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_gravity="bottom"
+ android:background="?android:attr/listDivider"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/navigation/integration-tests/testapp/src/main/res/layout/drawer_activity.xml b/navigation/integration-tests/testapp/src/main/res/layout/navigation_activity.xml
similarity index 100%
rename from navigation/integration-tests/testapp/src/main/res/layout/drawer_activity.xml
rename to navigation/integration-tests/testapp/src/main/res/layout/navigation_activity.xml
diff --git a/navigation/runtime/src/main/java/android/support/navigation/app/nav/NavController.java b/navigation/runtime/src/main/java/android/support/navigation/app/nav/NavController.java
index 377b732..cddbdc2 100644
--- a/navigation/runtime/src/main/java/android/support/navigation/app/nav/NavController.java
+++ b/navigation/runtime/src/main/java/android/support/navigation/app/nav/NavController.java
@@ -150,9 +150,15 @@
* Adds an {@link OnNavigatedListener} to this controller to receive events when
* the controller navigates to a new destination.
*
+ * <p>The current destination, if any, will be immediately sent to your listener.</p>
+ *
* @param listener the listener to receive events
*/
public void addOnNavigatedListener(OnNavigatedListener listener) {
+ // Inform the new listener of our current state, if any
+ if (!mBackStack.isEmpty()) {
+ listener.onNavigated(this, mBackStack.peekLast());
+ }
mOnNavigatedListeners.add(listener);
}