[go: nahoru, domu]

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()) {