Add getBackStackEntry that takes a route
There is currently no API to find a NavBackStackEntry using the route.
We should add one to match what we do with destination ids in base
Navigation.
RelNote: "Added a getBackStackEntry API that finds the NavBackStackEntry
using a route."
Test: NavHostControllerTest
Change-Id: If89316ee73218d779dfaa593eeba53a44d9dfb50
diff --git a/navigation/navigation-compose/api/current.txt b/navigation/navigation-compose/api/current.txt
index 7966498..e71f6e4 100644
--- a/navigation/navigation-compose/api/current.txt
+++ b/navigation/navigation-compose/api/current.txt
@@ -27,6 +27,7 @@
public final class NavHostControllerKt {
method public static androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+ method public static androidx.navigation.NavBackStackEntry getBackStackEntry(androidx.navigation.NavController, String route);
method public static void navigate(androidx.navigation.NavController, String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController();
field public static final String KEY_ROUTE = "android-support-nav:controller:route";
diff --git a/navigation/navigation-compose/api/public_plus_experimental_current.txt b/navigation/navigation-compose/api/public_plus_experimental_current.txt
index 7966498..e71f6e4 100644
--- a/navigation/navigation-compose/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-compose/api/public_plus_experimental_current.txt
@@ -27,6 +27,7 @@
public final class NavHostControllerKt {
method public static androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+ method public static androidx.navigation.NavBackStackEntry getBackStackEntry(androidx.navigation.NavController, String route);
method public static void navigate(androidx.navigation.NavController, String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController();
field public static final String KEY_ROUTE = "android-support-nav:controller:route";
diff --git a/navigation/navigation-compose/api/restricted_current.txt b/navigation/navigation-compose/api/restricted_current.txt
index 7966498..e71f6e4 100644
--- a/navigation/navigation-compose/api/restricted_current.txt
+++ b/navigation/navigation-compose/api/restricted_current.txt
@@ -27,6 +27,7 @@
public final class NavHostControllerKt {
method public static androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+ method public static androidx.navigation.NavBackStackEntry getBackStackEntry(androidx.navigation.NavController, String route);
method public static void navigate(androidx.navigation.NavController, String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController();
field public static final String KEY_ROUTE = "android-support-nav:controller:route";
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
index 829b1c12..5ba5c48 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostControllerTest.kt
@@ -35,6 +35,7 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import java.lang.IllegalArgumentException
@LargeTest
@RunWith(AndroidJUnit4::class)
@@ -189,6 +190,63 @@
.that(navigator.backStack.size)
.isEqualTo(2)
}
+
+ @Test
+ fun testGetBackStackEntry() {
+ lateinit var navController: NavController
+ composeTestRule.setContent {
+ navController = TestNavHostController(AmbientContext.current)
+
+ navController.graph = navController.createGraph(startDestination = FIRST_DESTINATION) {
+ test(FIRST_DESTINATION)
+ test(SECOND_DESTINATION)
+ }
+ }
+
+ composeTestRule.runOnUiThread {
+ navController.navigate(SECOND_DESTINATION)
+ }
+
+ assertWithMessage("first destination should be on back stack")
+ .that(
+ navController.getBackStackEntry(FIRST_DESTINATION).arguments?.getString(KEY_ROUTE)
+ )
+ .isEqualTo(FIRST_DESTINATION)
+
+ assertWithMessage("second destination should be on back stack")
+ .that(
+ navController.getBackStackEntry(SECOND_DESTINATION).arguments?.getString(KEY_ROUTE)
+ )
+ .isEqualTo(SECOND_DESTINATION)
+ }
+
+ @Test
+ fun testGetBackStackEntryNoEntryFound() {
+ lateinit var navController: NavController
+ composeTestRule.setContent {
+ navController = TestNavHostController(AmbientContext.current)
+
+ navController.graph = navController.createGraph(startDestination = FIRST_DESTINATION) {
+ test(FIRST_DESTINATION)
+ test(SECOND_DESTINATION)
+ }
+ }
+
+ composeTestRule.runOnUiThread {
+ navController.navigate(SECOND_DESTINATION)
+ }
+
+ try {
+ navController.getBackStackEntry(SECOND_DESTINATION)
+ } catch (e: IllegalArgumentException) {
+ assertThat(e)
+ .hasMessageThat().contains(
+ "No destination with route $SECOND_DESTINATION is on the NavController's " +
+ "back stack. The current destination is " +
+ navController.currentBackStackEntry?.destination
+ )
+ }
+ }
}
internal inline fun NavGraphBuilder.test(
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHostController.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHostController.kt
index f4ecc50..ea39658 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHostController.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHostController.kt
@@ -127,4 +127,25 @@
builder
)
+/**
+ * Gets the topmost {@link NavBackStackEntry} for a route.
+ * <p>
+ * This is always safe to use with {@link #getCurrentDestination() the current destination} or
+ * {@link NavDestination#getParent() its parent} or grandparent navigation graphs as these
+ * destinations are guaranteed to be on the back stack.
+ *
+ * @param route route of a destination that exists on the back stack
+ * @throws IllegalArgumentException if the destination is not on the back stack
+ */
+public fun NavController.getBackStackEntry(route: String): NavBackStackEntry {
+ try {
+ return getBackStackEntry(createRoute(route).hashCode())
+ } catch (e: IllegalArgumentException) {
+ throw IllegalArgumentException(
+ "No destination with route $route is on the NavController's back stack. The current " +
+ "destination is $currentDestination"
+ )
+ }
+}
+
internal fun createRoute(route: String) = "android-app://androidx.navigation.compose/$route"