Merge "Auto fill-in packageName for ${applicationId} pattern" into androidx-main am: fd8e6178f0
Original change: https://android-review.googlesource.com/c/platform/frameworks/support/+/2130557
Change-Id: I489c23451a4aa992c60944ee3b17c2e10f98212d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
index f0738a9..b9bc6fd 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
@@ -152,6 +152,69 @@
}
@Test
+ fun testInflateWithDataPatternApplicationId() {
+ val context = ApplicationProvider.getApplicationContext() as Context
+ val activityNavigator = ActivityNavigator(context)
+ val navInflater = NavInflater(
+ context,
+ TestNavigatorProvider().apply { addNavigator(activityNavigator) }
+ )
+
+ val graph = navInflater.inflate(R.navigation.nav_applicationid_arg)
+ val destination = graph.nodes.get(R.id.dataPattern_appId) as ActivityNavigator.Destination
+
+ assertThat(destination.dataPattern)
+ .isEqualTo("http://www.example.com/${context.packageName}")
+ }
+
+ @Test
+ fun testInflateWithNullDataPattern() {
+ val context = ApplicationProvider.getApplicationContext() as Context
+ val activityNavigator = ActivityNavigator(context)
+ val navInflater = NavInflater(
+ context,
+ TestNavigatorProvider().apply { addNavigator(activityNavigator) }
+ )
+
+ val graph = navInflater.inflate(R.navigation.nav_applicationid_arg)
+ val destination = graph.nodes.get(R.id.dataPattern_null) as ActivityNavigator.Destination
+
+ assertThat(destination.dataPattern).isNull()
+ }
+
+ @Test
+ fun testInflateWithDataApplicationId() {
+ val context = ApplicationProvider.getApplicationContext() as Context
+ val activityNavigator = ActivityNavigator(context)
+
+ val navInflater = NavInflater(
+ context,
+ TestNavigatorProvider().apply { addNavigator(activityNavigator) }
+ )
+
+ val graph = navInflater.inflate(R.navigation.nav_applicationid_arg)
+ val destination = graph.nodes.get(R.id.data_appId) as ActivityNavigator.Destination
+
+ assertThat(destination.data)
+ .isEqualTo(Uri.parse("http://www.example.com/${context.packageName}"))
+ }
+
+ @Test
+ fun testInflateWithNullData() {
+ val context = ApplicationProvider.getApplicationContext() as Context
+ val activityNavigator = ActivityNavigator(context)
+ val navInflater = NavInflater(
+ context,
+ TestNavigatorProvider().apply { addNavigator(activityNavigator) }
+ )
+
+ val graph = navInflater.inflate(R.navigation.nav_applicationid_arg)
+ val destination = graph.nodes.get(R.id.data_null) as ActivityNavigator.Destination
+
+ assertThat(destination.data).isNull()
+ }
+
+ @Test
fun testDefaultArgumentsInteger() {
val defaultArguments = inflateDefaultArgumentsFromGraph()
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml b/navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml
new file mode 100644
index 0000000..4c5ab73
--- /dev/null
+++ b/navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/nav_applicationid_arg"
+ app:startDestination="@+id/dataPattern_appId">
+
+ <activity android:id="@+id/dataPattern_appId"
+ app:dataPattern="http://www.example.com/${applicationId}">
+ </activity>
+ <activity android:id="@+id/dataPattern_null">
+ </activity>
+
+ <activity android:id="@+id/data_appId"
+ app:data="http://www.example.com/${applicationId}">
+ </activity>
+ <activity android:id="@+id/data_null">
+ </activity>
+</navigation>
\ No newline at end of file
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
index b1b9279..bb6e488 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
@@ -233,6 +233,10 @@
*
* If a non-null arguments Bundle is present when navigating, any segments in the form
* `{argName}` will be replaced with a URI encoded string from the arguments.
+ *
+ * When inflated from XML, you can use `${applicationId}` as an argument pattern
+ * to automatically use [Context.getPackageName].
+ *
* @param dataPattern A URI pattern with segments in the form of `{argName}` that
* will be replaced with URI encoded versions of the Strings in the
* arguments Bundle.
@@ -264,13 +268,10 @@
attrs,
R.styleable.ActivityNavigator
).use { array ->
- var targetPackage = array.getString(R.styleable.ActivityNavigator_targetPackage)
- if (targetPackage != null) {
- targetPackage = targetPackage.replace(
- NavInflater.APPLICATION_ID_PLACEHOLDER,
- context.packageName
- )
- }
+ var targetPackage = parseApplicationId(
+ context,
+ array.getString(R.styleable.ActivityNavigator_targetPackage)
+ )
setTargetPackage(targetPackage)
var className = array.getString(R.styleable.ActivityNavigator_android_name)
if (className != null) {
@@ -280,14 +281,28 @@
setComponentName(ComponentName(context, className))
}
setAction(array.getString(R.styleable.ActivityNavigator_action))
- val data = array.getString(R.styleable.ActivityNavigator_data)
+ val data = parseApplicationId(
+ context,
+ array.getString(R.styleable.ActivityNavigator_data)
+ )
if (data != null) {
setData(Uri.parse(data))
}
- setDataPattern(array.getString(R.styleable.ActivityNavigator_dataPattern))
+ val dataPattern = parseApplicationId(
+ context,
+ array.getString(R.styleable.ActivityNavigator_dataPattern)
+ )
+ setDataPattern(dataPattern)
}
}
+ private fun parseApplicationId(context: Context, pattern: String?): String? {
+ return pattern?.replace(
+ NavInflater.APPLICATION_ID_PLACEHOLDER,
+ context.packageName
+ )
+ }
+
/**
* The explicit application package name associated with this destination, if any
*/
@@ -370,6 +385,9 @@
* use [setDataPattern], which will take precedence when arguments are
* present.
*
+ * When inflated from XML, you can use `${applicationId}` for string interpolation
+ * to automatically use [Context.getPackageName].
+ *
* @param data A static URI that should always be used.
* @see Destination.setDataPattern
* @return this [Destination]