Fix handling of deep links without URIs
When declaring a deep link without a URI, any
processing related to extracting arguments
from a URI should be disabled rather than
crashing.
Updated handleDeepLink() to ensure that
all Intents are considered as possible deep links
rather than only Intent that have a data URI.
Test: added tests pass
BUG: 193805425
Change-Id: I50da0def710703bff93080348fe9bcec0e8b9e3e
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
index 2e42425..5a96c53 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
@@ -36,6 +36,18 @@
}
@Test
+ fun deepLinkNoUriNoMatch() {
+ val deepLink = NavDeepLink(null, "test.action", null)
+
+ assertWithMessage("NavDeepLink shouldn't match with null Uri")
+ .that(deepLink.matches(Uri.parse(DEEP_LINK_EXACT_HTTP)))
+ .isFalse()
+ assertWithMessage("NavDeepLink shouldn't find matching arguments with null Uri")
+ .that(deepLink.getMatchingArguments(Uri.parse(DEEP_LINK_EXACT_HTTP), mapOf()))
+ .isNull()
+ }
+
+ @Test
fun deepLinkExactMatch() {
val deepLink = NavDeepLink(DEEP_LINK_EXACT_HTTP)
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.kt
index d9acecd..ea99d5e 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.kt
@@ -150,7 +150,7 @@
deepLink: Uri,
arguments: Map<String, NavArgument?>
): Bundle? {
- val matcher = pattern!!.matcher(deepLink.toString())
+ val matcher = pattern?.matcher(deepLink.toString()) ?: return null
if (!matcher.matches()) {
return null
}
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 d17aa1d..ac372e4 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -27,6 +27,7 @@
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.addCallback
+import androidx.core.net.toUri
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
@@ -446,6 +447,24 @@
@UiThreadTest
@Test
+ fun testNavigateViaDeepLinkActionUnusedUri() {
+ val navController = createNavController()
+ navController.setGraph(R.navigation.nav_simple)
+ val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+ val action = "test.action"
+ val deepLink = NavDeepLinkRequest("http://www.example.com".toUri(), action, null)
+
+ navController.navigate(deepLink)
+ assertThat(navController.currentDestination?.id ?: 0).isEqualTo(R.id.second_test)
+ assertThat(navigator.backStack.size).isEqualTo(2)
+ val intent = navigator.current.arguments?.getParcelable<Intent>(
+ NavController.KEY_DEEP_LINK_INTENT
+ )
+ assertThat(intent?.action).isEqualTo(action)
+ }
+
+ @UiThreadTest
+ @Test
fun testNavigateViaDeepLinkActionDifferentURI() {
val navController = createNavController()
navController.setGraph(R.navigation.nav_simple)
@@ -1944,6 +1963,29 @@
@UiThreadTest
@Test
+ fun testHandleDeepLinkAction() {
+ val navController = createNavController()
+ navController.setGraph(R.navigation.nav_simple)
+ val collectedDestinationIds = mutableListOf<Int>()
+ navController.addOnDestinationChangedListener { _, destination, _ ->
+ collectedDestinationIds.add(destination.id)
+ }
+
+ val intent = Intent("test.action").apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ }
+ assertThat(intent).isNotNull()
+ assertWithMessage("NavController should handle deep links to its own graph")
+ .that(navController.handleDeepLink(intent))
+ .isTrue()
+ // Verify that we navigated down to the deep link
+ assertThat(collectedDestinationIds)
+ .containsExactly(R.id.start_test, R.id.start_test, R.id.second_test)
+ .inOrder()
+ }
+
+ @UiThreadTest
+ @Test
fun testHandleDeepLinkNestedStartDestination() {
val navController = createNavController()
navController.setGraph(R.navigation.nav_nested_start_destination)
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 d44d4de..6288a7d6 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
@@ -1007,14 +1007,16 @@
if (deepLinkExtras != null) {
globalArgs.putAll(deepLinkExtras)
}
- if ((deepLink == null || deepLink.isEmpty()) && intent.data != null) {
+ if (deepLink == null || deepLink.isEmpty()) {
val matchingDeepLink = _graph!!.matchDeepLink(NavDeepLinkRequest(intent))
if (matchingDeepLink != null) {
val destination = matchingDeepLink.destination
deepLink = destination.buildDeepLinkIds()
deepLinkArgs = null
val destinationArgs = destination.addInDefaultArgs(matchingDeepLink.matchingArgs)
- globalArgs.putAll(destinationArgs)
+ if (destinationArgs != null) {
+ globalArgs.putAll(destinationArgs)
+ }
}
}
if (deepLink == null || deepLink.isEmpty()) {