Skip to content

Commit 0df2dce

Browse files
authored
Merge 8339589 into 6f10a5b
2 parents 6f10a5b + 8339589 commit 0df2dce

12 files changed

Lines changed: 142 additions & 87 deletions

File tree

navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,7 @@ class NavDeepLinkTest {
210210
val id = 211
211211
val matchArgs = deepLink.getMatchingArguments(
212212
Uri.parse(deepLinkArgument.replace("{id}", id.toString())),
213-
mapOf(
214-
"id" to intArgument(),
215-
"myarg" to stringArgument()
216-
)
213+
mapOf("id" to intArgument())
217214
)
218215
assertWithMessage("Args should not be null")
219216
.that(matchArgs)
@@ -332,7 +329,7 @@ class NavDeepLinkTest {
332329

333330
val matchArgs = deepLink.getMatchingArguments(
334331
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users"),
335-
mapOf("myarg" to nullableStringArgument())
332+
mapOf("myarg" to nullableStringArgument(null))
336333
)
337334
assertWithMessage("Args should not be null")
338335
.that(matchArgs)
@@ -369,7 +366,7 @@ class NavDeepLinkTest {
369366

370367
val matchArgs = deepLink.getMatchingArguments(
371368
Uri.parse(deepLinkArgument),
372-
mapOf("myarg" to nullableStringArgument())
369+
mapOf("myarg" to nullableStringArgument(null))
373370
)
374371
assertWithMessage("Args should not be null")
375372
.that(matchArgs)
@@ -442,7 +439,7 @@ class NavDeepLinkTest {
442439
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users?id={id}".replace("{id}", id.toString())),
443440
mapOf(
444441
"id" to intArgument(),
445-
"optional" to nullableStringArgument()
442+
"optional" to nullableStringArgument(null)
446443
)
447444
)
448445
assertWithMessage("Args should not be null")
@@ -536,7 +533,7 @@ class NavDeepLinkTest {
536533

537534
val matchArgs = deepLink.getMatchingArguments(
538535
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users?id={id}&extraParam={extraParam}"),
539-
mapOf("myarg" to nullableStringArgument())
536+
mapOf("myarg" to nullableStringArgument(null))
540537
)
541538
assertWithMessage("Args should not be null")
542539
.that(matchArgs)
@@ -574,7 +571,7 @@ class NavDeepLinkTest {
574571

575572
val matchArgs = deepLink.getMatchingArguments(
576573
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users"),
577-
mapOf("myarg" to nullableStringArgument())
574+
mapOf("myarg" to nullableStringArgument(null))
578575
)
579576
assertWithMessage("Args should not be null")
580577
.that(matchArgs)
@@ -627,7 +624,7 @@ class NavDeepLinkTest {
627624

628625
val matchArgs = deepLink.getMatchingArguments(
629626
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users"),
630-
mapOf("myarg" to nullableStringArgument())
627+
mapOf("myarg" to nullableStringArgument(null))
631628
)
632629
assertWithMessage("Args should not be null")
633630
.that(matchArgs)
@@ -738,8 +735,8 @@ class NavDeepLinkTest {
738735
val matchArgs = deepLink.getMatchingArguments(
739736
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users"),
740737
mapOf(
741-
"first" to nullableStringArgument(),
742-
"last" to nullableStringArgument()
738+
"first" to nullableStringArgument(null),
739+
"last" to nullableStringArgument(null)
743740
)
744741
)
745742
assertWithMessage("Args should not be null")
@@ -799,7 +796,7 @@ class NavDeepLinkTest {
799796

800797
val matchArgs = deepLink.getMatchingArguments(
801798
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users?productId=wildCardMatch-{myarg}"),
802-
mapOf("myarg" to nullableStringArgument())
799+
mapOf("myarg" to nullableStringArgument(null))
803800
)
804801
assertWithMessage("Args should not be null")
805802
.that(matchArgs)
@@ -913,7 +910,7 @@ class NavDeepLinkTest {
913910

914911
val matchArgs = deepLink.getMatchingArguments(
915912
Uri.parse("$DEEP_LINK_EXACT_HTTPS/users"),
916-
mapOf("path" to nullableStringArgument())
913+
mapOf("path" to nullableStringArgument(null))
917914
)
918915
assertWithMessage("Args should not be null")
919916
.that(matchArgs)
@@ -1113,10 +1110,46 @@ class NavDeepLinkTest {
11131110
.replace("{param}", param.toString())
11141111
val matchArgs = deepLink.getMatchingArguments(
11151112
Uri.parse(deepLinkUpper),
1116-
mapOf("param" to intArgument())
1113+
mapOf("param" to intArgument(0))
11171114
)
11181115

1119-
assertWithMessage("Args should be not be null")
1116+
assertWithMessage("Args should not be null")
1117+
.that(matchArgs)
1118+
.isNotNull()
1119+
assertWithMessage("Args bundle should be empty")
1120+
.that(matchArgs?.isEmpty)
1121+
.isTrue()
1122+
}
1123+
1124+
@Test
1125+
fun deepLinkMissingRequiredArgument() {
1126+
val deepLinkString = "$DEEP_LINK_EXACT_HTTPS/greeting?title={title}&text={text}"
1127+
val deepLink = NavDeepLink(deepLinkString)
1128+
1129+
val matchArgs = deepLink.getMatchingArguments(
1130+
Uri.parse("$DEEP_LINK_EXACT_HTTPS/greeting?title=No%20text"),
1131+
mapOf(
1132+
"title" to stringArgument(),
1133+
"text" to stringArgument()
1134+
)
1135+
)
1136+
1137+
assertWithMessage("Args should be null")
1138+
.that(matchArgs)
1139+
.isNull()
1140+
}
1141+
1142+
@Test
1143+
fun deepLinkMissingOptionalArgument() {
1144+
val deepLinkString = "$DEEP_LINK_EXACT_HTTPS/greeting?text={text}"
1145+
val deepLink = NavDeepLink(deepLinkString)
1146+
1147+
val matchArgs = deepLink.getMatchingArguments(
1148+
Uri.parse("$DEEP_LINK_EXACT_HTTPS/greeting"),
1149+
mapOf("text" to stringArgument("Default greeting"))
1150+
)
1151+
1152+
assertWithMessage("Args should not be null")
11201153
.that(matchArgs)
11211154
.isNotNull()
11221155
assertWithMessage("Args bundle should be empty")

navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationAndroidTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import android.os.Bundle
2121
import androidx.core.net.toUri
2222
import androidx.navigation.NavDestination.Companion.createRoute
2323
import androidx.navigation.test.intArgument
24+
import androidx.navigation.test.nullableStringArgument
2425
import androidx.navigation.test.stringArgument
2526
import androidx.test.filters.SmallTest
2627
import com.google.common.truth.Truth.assertThat
@@ -116,7 +117,7 @@ class NavDestinationAndroidTest {
116117

117118
destination.addDeepLink("www.example.com/users/index.html")
118119

119-
destination.addArgument("name", stringArgument())
120+
destination.addArgument("name", nullableStringArgument(null))
120121
destination.addDeepLink("www.example.com/users/{name}")
121122

122123
val match = destination.matchDeepLink(
@@ -138,7 +139,7 @@ class NavDestinationAndroidTest {
138139
destination.addArgument("tab", stringArgument())
139140
destination.addDeepLink("www.example.com/users/anonymous?tab={tab}")
140141

141-
destination.addArgument("name", stringArgument())
142+
destination.addArgument("name", nullableStringArgument(null))
142143
destination.addDeepLink("www.example.com/users/{name}?tab={tab}")
143144

144145
val match = destination.matchDeepLink(
@@ -224,15 +225,15 @@ class NavDestinationAndroidTest {
224225
fun matchDeepLinkBestMimeType() {
225226
val destination = NoOpNavigator().createDestination()
226227

227-
destination.addArgument("deeplink1", stringArgument())
228+
destination.addArgument("deeplink1", nullableStringArgument(null))
228229
destination.addDeepLink(
229230
NavDeepLink(
230231
"www.example.com/users/{deeplink1}",
231232
null, "*/*"
232233
)
233234
)
234235

235-
destination.addArgument("deeplink2", stringArgument())
236+
destination.addArgument("deeplink2", nullableStringArgument(null))
236237
destination.addDeepLink(
237238
NavDeepLink(
238239
"www.example.com/users/{deeplink2}",
@@ -281,9 +282,8 @@ class NavDestinationAndroidTest {
281282
val destination = NoOpNavigator().createDestination()
282283
destination.addArgument("testString", stringArgument())
283284
destination.addDeepLink("android-app://androidx.navigation.test/{testString}")
284-
val deepLink = Uri.parse("android-app://androidx.navigation.test/test")
285-
destination.addDeepLink(deepLink.toString())
286285

286+
val deepLink = Uri.parse("android-app://androidx.navigation.test/test")
287287
assertWithMessage("Deep link should match")
288288
.that(destination.hasDeepLink(deepLink)).isTrue()
289289
}

navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphAndroidTest.kt

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package androidx.navigation
1818

1919
import android.net.Uri
20+
import androidx.navigation.test.nullableStringArgument
2021
import androidx.test.filters.SmallTest
2122
import com.google.common.truth.Truth.assertThat
2223
import com.google.common.truth.Truth.assertWithMessage
@@ -70,11 +71,8 @@ class NavGraphAndroidTest {
7071

7172
graph.addDeepLink("www.example.com/users/index.html")
7273

73-
val idArgument = NavArgument.Builder()
74-
.setType(NavType.StringType)
75-
.build()
76-
graph.addArgument("id", idArgument)
77-
graph.addDeepLink("www.example.com/users/{name}")
74+
graph.addArgument("id", nullableStringArgument(null))
75+
graph.addDeepLink("www.example.com/users/{id}")
7876

7977
val match = graph.matchDeepLink(
8078
Uri.parse("https://www.example.com/users/index.html")
@@ -155,16 +153,10 @@ class NavGraphAndroidTest {
155153
val graph = navigatorProvider.getNavigator(NavGraphNavigator::class.java)
156154
.createDestination()
157155

158-
val codeArgument = NavArgument.Builder()
159-
.setType(NavType.StringType)
160-
.build()
161-
graph.addArgument("code", codeArgument)
156+
graph.addArgument("code", nullableStringArgument(null))
162157
graph.addDeepLink("www.example.com/users?code={code}")
163158

164-
val idArgument = NavArgument.Builder()
165-
.setType(NavType.StringType)
166-
.build()
167-
graph.addArgument("id", idArgument)
159+
graph.addArgument("id", nullableStringArgument(null))
168160
graph.addDeepLink("www.example.com/users?id={id}")
169161

170162
val match = graph.matchDeepLink(

navigation/navigation-common/src/androidTest/java/androidx/navigation/test/NavArgument.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,11 @@ fun stringArgument(
7777
.setDefaultValue(defaultValue)
7878
.build()
7979

80-
fun nullableStringArgument() = NavArgument.Builder().setType(StringType)
80+
fun nullableStringArgument(
81+
defaultValue: String?
82+
) = NavArgument.Builder().setType(StringType)
8183
.setIsNullable(true)
84+
.setDefaultValue(defaultValue)
8285
.build()
8386
// endregion
8487

@@ -89,4 +92,4 @@ fun stringArrayArgument(
8992
.setIsNullable(true)
9093
.setDefaultValue(defaultValue)
9194
.build()
92-
// endregion
95+
// endregion

navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public class NavDeepLink internal constructor(
5454

5555
private var mimeTypePattern: Pattern? = null
5656

57+
/** Arguments present in the deep link, including both path and query arguments. */
58+
internal val argumentsNames: List<String>
59+
get() = arguments + paramArgMap.keys
60+
5761
public var isExactDeepLink: Boolean = false
5862
/** @suppress */
5963
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -192,6 +196,13 @@ public class NavDeepLink internal constructor(
192196
}
193197
}
194198
}
199+
200+
// Check that all required arguments are present in bundle
201+
for ((argName, argument) in arguments.entries) {
202+
val argumentIsRequired = argument != null && !argument.isDefaultValuePresent
203+
if (argumentIsRequired && !bundle.containsKey(argName)) return null
204+
}
205+
195206
return bundle
196207
}
197208

@@ -283,7 +294,8 @@ public class NavDeepLink internal constructor(
283294
public class Builder {
284295

285296
/** @suppress */
286-
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public constructor()
297+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
298+
public constructor()
287299

288300
private var uriPattern: String? = null
289301
private var action: String? = null

navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,14 @@ public open class NavDestination(
315315
* @see NavController.navigate
316316
*/
317317
public fun addDeepLink(navDeepLink: NavDeepLink) {
318+
val missingRequiredArguments = arguments.filterValues { !it.isDefaultValuePresent }
319+
.keys
320+
.filter { it !in navDeepLink.argumentsNames }
321+
require(missingRequiredArguments.isEmpty()) {
322+
"Deep link ${navDeepLink.uriPattern} can't be used to open destination $this.\n" +
323+
"Following required arguments are missing: $missingRequiredArguments"
324+
}
325+
318326
deepLinks.add(navDeepLink)
319327
}
320328

navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerActivityTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class NavControllerActivityTest {
7575
navController.setGraph(R.navigation.nav_simple)
7676
navController.handleDeepLink(
7777
Intent().apply {
78-
data = Uri.parse("android-app://androidx.navigation.test/test")
78+
data = Uri.parse("android-app://androidx.navigation.test/test/arg2")
7979
}
8080
)
8181
assertThat(navController.currentDestination?.id)
@@ -97,7 +97,7 @@ class NavControllerActivityTest {
9797
val activity = activityRule.activity
9898

9999
val intent = Intent().apply {
100-
data = Uri.parse("android-app://androidx.navigation.test/test")
100+
data = Uri.parse("android-app://androidx.navigation.test/test/arg2")
101101
}
102102

103103
activity.intent = intent

0 commit comments

Comments
 (0)