Merge "Express -ktx atomic versioning constraints in Gradle metadata" into androidx-main am: 1f8e970e5b

Original change: https://android-review.googlesource.com/c/platform/frameworks/support/+/1973425

Change-Id: I75826c0e96794430f65997c6c77007baa40780eb
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/activity/activity-ktx/build.gradle b/activity/activity-ktx/build.gradle
index 21e4e1a..57e4406 100644
--- a/activity/activity-ktx/build.gradle
+++ b/activity/activity-ktx/build.gradle
@@ -24,6 +24,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":activity:activity"))
+    }
+
     api(project(":activity:activity"))
     api("androidx.core:core-ktx:1.1.0") {
         because "Mirror activity dependency graph for -ktx artifacts"
diff --git a/activity/activity/build.gradle b/activity/activity/build.gradle
index f73ad5a..8a76573 100644
--- a/activity/activity/build.gradle
+++ b/activity/activity/build.gradle
@@ -15,6 +15,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":activity:activity-ktx"))
+    }
+
     api("androidx.annotation:annotation:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api(projectOrArtifact(":core:core"))
diff --git a/biometric/biometric-ktx/build.gradle b/biometric/biometric-ktx/build.gradle
index ec70a1c..22a6f56 100755
--- a/biometric/biometric-ktx/build.gradle
+++ b/biometric/biometric-ktx/build.gradle
@@ -23,6 +23,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":biometric:biometric-ktx"))
+    }
+
     api(libs.kotlinStdlib)
     api(libs.kotlinCoroutinesCore)
     api(project(":biometric:biometric"))
diff --git a/biometric/biometric/build.gradle b/biometric/biometric/build.gradle
index 1f3a000..9b82c05 100644
--- a/biometric/biometric/build.gradle
+++ b/biometric/biometric/build.gradle
@@ -28,6 +28,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":biometric:biometric-ktx"))
+    }
+
     // Public API dependencies
     api("androidx.annotation:annotation:1.1.0")
     api("androidx.core:core:1.3.2")
diff --git a/compose/ui/ui-viewbinding/samples/build.gradle b/compose/ui/ui-viewbinding/samples/build.gradle
index b9a6b53..64a65d0 100644
--- a/compose/ui/ui-viewbinding/samples/build.gradle
+++ b/compose/ui/ui-viewbinding/samples/build.gradle
@@ -57,11 +57,3 @@
     }
     namespace "androidx.compose.ui.viewbinding.samples"
 }
-
-// Workaround for https://github.com/gradle/gradle/issues/19882
-configurations.all {
-    resolutionStrategy.dependencySubstitution {
-        substitute(module("androidx.lifecycle:lifecycle-common-java8:")).
-                using project(":lifecycle:lifecycle-common-java8")
-    }
-}
diff --git a/core/core-ktx/build.gradle b/core/core-ktx/build.gradle
index 3905f13..97233be 100644
--- a/core/core-ktx/build.gradle
+++ b/core/core-ktx/build.gradle
@@ -7,6 +7,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":core:core"))
+    }
+
     api(libs.kotlinStdlib)
     api("androidx.annotation:annotation:1.1.0")
     api(project(":core:core"))
diff --git a/core/core/build.gradle b/core/core/build.gradle
index 2c85ed0..7815d5b 100644
--- a/core/core/build.gradle
+++ b/core/core/build.gradle
@@ -7,6 +7,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":core:core-ktx"))
+    }
+
     api("androidx.annotation:annotation:1.2.0")
     api("androidx.annotation:annotation-experimental:1.1.0")
     api("androidx.lifecycle:lifecycle-runtime:2.3.1")
diff --git a/core/core/integration-tests/publishing/build.gradle b/core/core/integration-tests/publishing/build.gradle
new file mode 100644
index 0000000..6d9b83e
--- /dev/null
+++ b/core/core/integration-tests/publishing/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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.
+ */
+
+import androidx.build.SdkResourceGenerator
+
+plugins {
+    id("AndroidXPlugin")
+    id("kotlin")
+}
+
+dependencies {
+    implementation(libs.kotlinStdlib)
+
+    testImplementation(project(":internal-testutils-gradle-plugin"))
+    testImplementation(libs.junit)
+    testImplementation(libs.truth)
+    testImplementation(gradleTestKit())
+}
+
+SdkResourceGenerator.generateForHostTest(project)
+
+tasks.named("test").configure {
+    dependsOn(":core:core:publish")
+    dependsOn(":core:core-ktx:publish")
+}
diff --git a/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt b/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt
new file mode 100644
index 0000000..f0e3ef7
--- /dev/null
+++ b/core/core/integration-tests/publishing/src/test/kotlin/androidx/build/ConstraintTest.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+package androidx.build
+
+import androidx.testutils.gradle.ProjectSetupRule
+import java.io.File
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+class ConstraintTest {
+    @get:Rule
+    val projectSetup = ProjectSetupRule()
+
+    /**
+     * Test for matching constraint versions in Gradle metadata.
+     */
+    @Test
+    fun mavenMetadataRequiresVersion() {
+        val baseMavenMetadata = getPublishedFile("androidx/core/core/maven-metadata.xml")
+        val baseVersion = getLatestVersion(baseMavenMetadata)
+
+        val baseGradleMetadata =
+            getPublishedFile("androidx/core/core/$baseVersion/core-$baseVersion.module")
+        val baseRequiresKtxVersion =
+            getConstraintVersion(baseGradleMetadata.readText(), "androidx.core", "core-ktx")!!
+
+        val ktxMavenMetadata = getPublishedFile("androidx/core/core-ktx/maven-metadata.xml")
+        val ktxVersion = getLatestVersion(ktxMavenMetadata)
+
+        val ktxGradleMetadata =
+            getPublishedFile("androidx/core/core-ktx/$ktxVersion/core-ktx-$ktxVersion.module")
+        val ktxRequiresBaseVersion =
+            getConstraintVersion(ktxGradleMetadata.readText(), "androidx.core", "core")!!
+
+        // The core and core-ktx libraries should share the same version.
+        assertEquals(baseVersion, ktxVersion)
+
+        // Their Gradle metadata files should reference each other as `required`-type constraints.
+        assertEquals(baseVersion, ktxRequiresBaseVersion)
+        assertEquals(ktxVersion, baseRequiresKtxVersion)
+    }
+
+    /**
+     * Unit test for the constraint version extraction function.
+     */
+    @Test
+    fun getConstraintVersionTest() {
+        val metadata = """
+              "version": {
+                "requires": "1.0.0"
+              }
+            }
+          ],
+          "dependencyConstraints": [
+            {
+              "group": "androidx.preference",
+              "module": "preference-ktx",
+              "version": {
+                "requires": "1.3.0-alpha01"
+              }
+            }
+          ],
+          "files": [
+            {
+              "name": "preference-1.3.0-alpha01.aar",
+              "url": "preference-1.3.0-alpha01.aar",
+        """.trimIndent()
+
+        val requiresVersion =
+            getConstraintVersion(metadata, "androidx.preference", "preference-ktx")
+        assertEquals("1.3.0-alpha01", requiresVersion)
+    }
+
+    private fun getConstraintVersion(metadata: String, groupId: String, artifact: String): String? =
+        getDependencyConstraints(metadata)?.let {
+            Regex(
+                "\"group\": \"$groupId\",\\s+\"module\": " +
+                    "\"$artifact\",\\s+\"version\": \\{\\s+\"requires\": \"(.+?)\""
+            ).find(it)?.groups?.get(1)?.value
+        }
+
+    private fun getDependencyConstraints(moduleJson: String) = moduleJson.let {
+        Regex("(?s)\"dependencyConstraints\": \\[(.+?)]").find(it)?.groups?.get(1)?.value
+    }
+
+    // Yes, I know https://stackoverflow.com/a/1732454/258688, but it's just a test...
+    private fun getLatestVersion(metadataFile: File) = metadataFile.readLines()
+        .mapNotNull { Regex(".*<latest>(.*?)</latest>.*").find(it)?.groups?.get(1)?.value }.first()
+
+    private fun getPublishedFile(name: String) =
+        File(projectSetup.props.tipOfTreeMavenRepoPath).resolve(name).check { it.exists() }
+
+    private fun <T> T.check(eval: (T) -> Boolean): T {
+        if (!eval(this)) {
+            Assert.fail("Failed assertion: $this")
+        }
+        return this
+    }
+}
diff --git a/palette/palette-ktx/build.gradle b/palette/palette-ktx/build.gradle
index 0fbe185..4e09042 100644
--- a/palette/palette-ktx/build.gradle
+++ b/palette/palette-ktx/build.gradle
@@ -23,6 +23,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":palette:palette"))
+    }
+
     api(project(":palette:palette"))
     api(libs.kotlinStdlib)
     androidTestImplementation(libs.junit)
diff --git a/palette/palette/build.gradle b/palette/palette/build.gradle
index 14f3c00..573af81 100644
--- a/palette/palette/build.gradle
+++ b/palette/palette/build.gradle
@@ -6,6 +6,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":palette:palette-ktx"))
+    }
+
     api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
diff --git a/preference/preference-ktx/build.gradle b/preference/preference-ktx/build.gradle
index b10c5b1..91ab34a 100644
--- a/preference/preference-ktx/build.gradle
+++ b/preference/preference-ktx/build.gradle
@@ -23,6 +23,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":preference:preference"))
+    }
+
     api(project(":preference:preference"))
     api("androidx.core:core-ktx:1.1.0") {
         because "Mirror preference dependency graph for -ktx artifacts"
diff --git a/preference/preference/build.gradle b/preference/preference/build.gradle
index 73f104c..782614b 100644
--- a/preference/preference/build.gradle
+++ b/preference/preference/build.gradle
@@ -23,6 +23,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":preference:preference-ktx"))
+    }
+
     api("androidx.annotation:annotation:1.2.0")
     api("androidx.appcompat:appcompat:1.1.0")
     // Use the latest version of core library for verifying insets visibility
diff --git a/savedstate/savedstate-ktx/build.gradle b/savedstate/savedstate-ktx/build.gradle
index e09dc9f..7f5e440 100644
--- a/savedstate/savedstate-ktx/build.gradle
+++ b/savedstate/savedstate-ktx/build.gradle
@@ -23,6 +23,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":savedstate:savedstate"))
+    }
+
     api(project(":savedstate:savedstate"))
     api(libs.kotlinStdlib)
 
diff --git a/savedstate/savedstate/build.gradle b/savedstate/savedstate/build.gradle
index fb3aa36..ca99126 100644
--- a/savedstate/savedstate/build.gradle
+++ b/savedstate/savedstate/build.gradle
@@ -14,6 +14,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":savedstate:savedstate-ktx"))
+    }
+
     api("androidx.annotation:annotation:1.1.0")
     implementation("androidx.arch.core:core-common:2.1.0")
     implementation("androidx.lifecycle:lifecycle-common:2.4.0")
diff --git a/settings.gradle b/settings.gradle
index 2353e32..ec6c0da 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -280,7 +280,7 @@
 includeProject(":activity:activity-compose:activity-compose-samples", "activity/activity-compose/samples", [BuildType.COMPOSE])
 includeProject(":activity:activity-compose:integration-tests:activity-demos", [BuildType.COMPOSE])
 includeProject(":activity:activity-compose-lint", [BuildType.COMPOSE])
-includeProject(":activity:activity-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE])
+includeProject(":activity:activity-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":activity:activity-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":activity:integration-tests:testapp", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":ads:ads-identifier", [BuildType.MAIN])
@@ -507,14 +507,15 @@
 includeProject(":concurrent:concurrent-futures-ktx", [BuildType.MAIN])
 includeProject(":contentpager:contentpager", [BuildType.MAIN])
 includeProject(":coordinatorlayout:coordinatorlayout", [BuildType.MAIN])
-includeProject(":core:core", [BuildType.MAIN, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
+includeProject(":core:core", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
+includeProject(":core:core:integration-tests:publishing", [BuildType.MAIN])
 includeProject(":core:core-animation", [BuildType.MAIN])
 includeProject(":core:core-animation-integration-tests:testapp", [BuildType.MAIN])
 includeProject(":core:core-animation-testing", [BuildType.MAIN])
 includeProject(":core:core-appdigest", [BuildType.MAIN])
 includeProject(":core:core-google-shortcuts", [BuildType.MAIN])
 includeProject(":core:core-i18n", [BuildType.MAIN])
-includeProject(":core:core-ktx", [BuildType.MAIN, BuildType.GLANCE])
+includeProject(":core:core-ktx", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":core:core-performance", [BuildType.MAIN])
 includeProject(":core:core-performance:core-performance-samples", "core/core-performance/samples", [BuildType.MAIN])
 includeProject(":core:core-remoteviews", [BuildType.MAIN, BuildType.GLANCE])
@@ -728,7 +729,7 @@
 includeProject(":room:room-rxjava3", [BuildType.MAIN])
 includeProject(":room:room-testing", [BuildType.MAIN])
 includeProject(":savedstate:savedstate", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.WEAR])
-includeProject(":savedstate:savedstate-ktx", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN])
+includeProject(":savedstate:savedstate-ktx", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.WEAR])
 includeProject(":security:security-app-authenticator", [BuildType.MAIN])
 includeProject(":security:security-app-authenticator-testing", [BuildType.MAIN])
 includeProject(":security:security-biometric", [BuildType.MAIN])
@@ -881,7 +882,7 @@
 includeProject(":internal-testutils-runtime", "testutils/testutils-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.MEDIA, BuildType.WEAR])
 includeProject(":internal-testutils-appcompat", "testutils/testutils-appcompat", [BuildType.MAIN])
 includeProject(":internal-testutils-espresso", "testutils/testutils-espresso", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":internal-testutils-truth", "testutils/testutils-truth", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE])
+includeProject(":internal-testutils-truth", "testutils/testutils-truth", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":internal-testutils-ktx", "testutils/testutils-ktx")
 includeProject(":internal-testutils-macrobenchmark", "testutils/testutils-macrobenchmark", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":internal-testutils-navigation", "testutils/testutils-navigation", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN])
diff --git a/wear/compose/compose-material/samples/build.gradle b/wear/compose/compose-material/samples/build.gradle
index 7b1743a..a46003b 100644
--- a/wear/compose/compose-material/samples/build.gradle
+++ b/wear/compose/compose-material/samples/build.gradle
@@ -61,11 +61,3 @@
     inceptionYear = "2021"
     description = "Contains the sample code for the Android Wear Compose Material Classes"
 }
-
-// Workaround for https://github.com/gradle/gradle/issues/19882
-configurations.all {
-    resolutionStrategy.dependencySubstitution {
-        substitute(module("androidx.lifecycle:lifecycle-common-java8:")).
-                using project(":lifecycle:lifecycle-common-java8")
-    }
-}