[go: nahoru, domu]

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"