Fix missing non-nullable arg when rebuilding hierarchy

When navigating with NavDirections, args is populated with an empty bundle. This causes issue when we rebuild parent hierarchy while adding a new entry to NavBackStack. If the Entry being rebuilt contains a non-nullalbe arg, i.e. Long, this empty bundle will cause an exception.

Test: ./gradlew navigation:navigation-runtime:cC
Bug: 249988437
Change-Id: I5c8ce739ad9a3428c8a8de13eae391bfff0db5df
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
index abb391c..5e04fc2 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -58,6 +58,7 @@
 import androidx.testutils.test
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import kotlin.test.assertFailsWith
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.take
@@ -104,6 +105,22 @@
             }
     }
 
+    private val NESTED_NAV_GRAPH_2 =
+        navController.createGraph(route = "graph", startDestination = "dest1") {
+            test("dest1")
+            navigation(route = "nested", startDestination = "dest2") {
+                argument("longArg") {
+                    type = NavType.LongType
+                }
+                test("dest2") {
+                    argument("longArg") {
+                        type = NavType.LongType
+                    }
+                }
+                test("dest3")
+            }
+        }
+
     @UiThreadTest
     @Test
     fun testGetCurrentBackStackEntry() {
@@ -1653,6 +1670,23 @@
 
     @UiThreadTest
     @Test
+    fun testNavigateWithMissingNonNullableArg() {
+        val navController = createNavController()
+        navController.graph = NESTED_NAV_GRAPH_2
+        assertThat(navController.currentDestination?.route).isEqualTo("dest1")
+
+        val nestedId = ("android-app://androidx.navigation/nested").hashCode()
+
+        val expected = assertFailsWith<NullPointerException> {
+            navController.navigate(nestedId)
+        }
+        assertThat(expected.message).isEqualTo(
+            "null cannot be cast to non-null type kotlin.Long"
+        )
+    }
+
+    @UiThreadTest
+    @Test
     fun testNavigateMultipleParentsOnHierarchy() {
         val navController = createNavController()
         navController.setGraph(R.navigation.nav_root)
@@ -1670,6 +1704,34 @@
 
     @UiThreadTest
     @Test
+    fun testRebuildParentWithMissingNonNullableArg() {
+        val navController = createNavController()
+        navController.graph = NESTED_NAV_GRAPH_2
+        assertThat(navController.currentDestination?.route).isEqualTo("dest1")
+
+        val nestedId1 = ("android-app://androidx.navigation/nested").hashCode()
+
+        // navigate to nested graph first destination, provide non-nullable arg
+        navController.navigate(
+            nestedId1,
+            bundleOf("longArg" to 123L)
+        )
+        assertThat(navController.currentDestination?.route).isEqualTo("dest2")
+
+        val nestedId2 = ("android-app://androidx.navigation/dest3").hashCode()
+        // navigate to nested graph second destination after popping up to graph (inclusive)
+        // empty bundle to imitate navigating with NavDirections
+        navController.navigate(
+            nestedId2,
+            Bundle(),
+            NavOptions.Builder().setPopUpTo("nested", inclusive = true).build()
+        )
+        // [graph, dest1, nested, dest3]
+        assertThat(navController.currentBackStack.value.size).isEqualTo(4)
+    }
+
+    @UiThreadTest
+    @Test
     fun testNavigateWithOverriddenDefaultArgs() {
         val args = Bundle()
         args.putString(TEST_OVERRIDDEN_VALUE_ARG, TEST_OVERRIDDEN_VALUE_ARG_VALUE)
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
index 9c54f99..302dc96 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
@@ -2045,10 +2045,11 @@
         while (destination != null && findDestination(destination.id) !== destination) {
             val parent = destination.parent
             if (parent != null) {
+                val args = if (finalArgs?.isEmpty == true) null else finalArgs
                 val entry = restoredEntries.lastOrNull { restoredEntry ->
                     restoredEntry.destination == parent
                 } ?: NavBackStackEntry.create(
-                    context, parent, parent.addInDefaultArgs(finalArgs), hostLifecycleState,
+                    context, parent, parent.addInDefaultArgs(args), hostLifecycleState,
                     viewModel
                 )
                 hierarchy.addFirst(entry)