Add Kotlin support for testFixtures and screenshotTest in AGP

This change adds support for kotlin compilation in testFixtures with the
android.experimental.enableTestFixturesKotlinSupport Gradle property.

Similarly, kotlin compilation is enabled for screenshotTest with the
existing android.experimental.enableScreenshotTest Gradle property.

Bug: 259523353
Test: TestFixturesKotlinTest, ComposeHelloWorldTest, etc.

Change-Id: I35d20ba04d323529b0f35ad81ee8ed2ee58dd083
diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt
index 9a18b8e..2232ca0 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt
@@ -178,6 +178,8 @@
         ProductFlavor(it.first, it.second)
     }
 
+    override val useBuiltInKotlinSupport: Boolean = false
+
     // ---------------------------------------------------------------------------------------------
     // Private stuff
     // ---------------------------------------------------------------------------------------------
diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/HostTestImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/HostTestImpl.kt
index efaf194..3a904c2 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/HostTestImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/HostTestImpl.kt
@@ -59,6 +59,7 @@
     global: GlobalTaskCreationConfig,
     hostTestBuilder: HostTestBuilderImpl,
     override val hostTestName: String,
+    override val useBuiltInKotlinSupport: Boolean,
 ) : TestComponentImpl<HostTestComponentDslInfo>(
     componentIdentity,
     buildFeatureValues,
diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/KmpComponentImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/KmpComponentImpl.kt
index e1c26b7..8e7dfe8 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/KmpComponentImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/KmpComponentImpl.kt
@@ -68,7 +68,6 @@
 import com.android.builder.core.ComponentType
 import com.android.utils.appendCapitalized
 import org.gradle.api.artifacts.Configuration
-import org.gradle.api.file.Directory
 import org.gradle.api.file.FileCollection
 import org.gradle.api.provider.Provider
 import org.gradle.api.tasks.util.PatternSet
@@ -136,6 +135,8 @@
     override val minSdk: AndroidVersion
         get() = dslInfo.minSdkVersion
 
+    final override val useBuiltInKotlinSupport = false
+
     override val sources = KmpSourcesImpl(
         dslInfo,
         internalServices,
diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ScreenshotTestImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ScreenshotTestImpl.kt
index 54c804a..20de4fb 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ScreenshotTestImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ScreenshotTestImpl.kt
@@ -68,4 +68,5 @@
     global,
     hostTestBuilder,
     HostTestBuilder.SCREENSHOT_TEST_TYPE,
+    useBuiltInKotlinSupport = true
 ), HostTestCreationConfig
diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt
index 791b41b..6bc51aa 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt
@@ -43,7 +43,9 @@
 import com.android.build.gradle.internal.tasks.AarMetadataTask.Companion.DEFAULT_MIN_COMPILE_SDK_EXTENSION
 import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig
 import com.android.build.gradle.internal.testFixtures.testFixturesFeatureName
+import com.android.build.gradle.internal.utils.isKotlinBaseApiPluginApplied
 import com.android.build.gradle.internal.variant.VariantPathHelper
+import com.android.build.gradle.options.BooleanOption
 import com.android.builder.core.BuilderConstants
 import com.android.utils.appendCapitalized
 import com.android.utils.capitalizeAndAppend
@@ -167,4 +169,8 @@
     override fun getArtifactName(name: String): String {
         return "$testFixturesFeatureName-$name"
     }
+
+    override val useBuiltInKotlinSupport: Boolean =
+        internalServices.projectOptions.get(BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT)
+                && isKotlinBaseApiPluginApplied(internalServices.projectInfo)
 }
diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt
index 70e5e82..3e83179 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt
@@ -70,6 +70,7 @@
     global,
     hostTestBuilder,
     HostTestBuilder.UNIT_TEST_TYPE,
+    useBuiltInKotlinSupport = false
 ), UnitTest {
 
     /**
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/TaskManager.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/TaskManager.kt
index 9685cd8..27cf91b 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/TaskManager.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/TaskManager.kt
@@ -131,6 +131,7 @@
 import com.android.build.gradle.internal.testing.utp.TEST_RESULT_PB_FILE_NAME
 import com.android.build.gradle.internal.transforms.ShrinkAppBundleResourcesTask
 import com.android.build.gradle.internal.transforms.ShrinkResourcesNewShrinkerTask
+import com.android.build.gradle.internal.utils.checkKotlinStdLibIsInDependencies
 import com.android.build.gradle.internal.utils.getProjectKotlinPluginKotlinVersion
 import com.android.build.gradle.internal.utils.isKotlinKaptPluginApplied
 import com.android.build.gradle.internal.utils.isKspPluginApplied
@@ -144,6 +145,7 @@
 import com.android.build.gradle.tasks.GenerateResValues
 import com.android.build.gradle.tasks.JavaCompileCreationAction
 import com.android.build.gradle.tasks.JavaPreCompileTask
+import com.android.build.gradle.tasks.KotlinCompileCreationAction
 import com.android.build.gradle.tasks.ManifestProcessorTask
 import com.android.build.gradle.tasks.MapSourceSetPathsTask
 import com.android.build.gradle.tasks.MergeResources
@@ -856,7 +858,18 @@
                 )
         }
 
-       creationConfig
+        if (creationConfig.useBuiltInKotlinSupport) {
+            creationConfig
+                .artifacts
+                .forScope(ScopedArtifacts.Scope.PROJECT)
+                .setInitialContent(
+                    ScopedArtifact.CLASSES,
+                    creationConfig.artifacts,
+                    InternalArtifactType.KOTLINC
+                )
+        }
+
+        creationConfig
            .artifacts
            .forScope(ScopedArtifacts.Scope.PROJECT)
            .setInitialContent(
@@ -874,6 +887,8 @@
     protected fun createJavacTask(
             creationConfig: ComponentCreationConfig
     ): TaskProvider<out JavaCompile> {
+        maybeCreateKotlinTasks(creationConfig)
+
         val usingKapt = isKotlinKaptPluginApplied(project)
         val usingKsp = isKspPluginApplied(project)
         taskFactory.register(JavaPreCompileTask.CreationAction(creationConfig, usingKapt, usingKsp))
@@ -889,6 +904,14 @@
         return javacTask
     }
 
+    private fun maybeCreateKotlinTasks(creationConfig: ComponentCreationConfig) {
+        if (!creationConfig.useBuiltInKotlinSupport) {
+            return
+        }
+        checkKotlinStdLibIsInDependencies(project, creationConfig)
+        KotlinCompileCreationAction(creationConfig).registerTask()
+    }
+
     /**
      * Creates the individual managed device tasks for the given variant
      *
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt
index 62cb5ad..822b4d6 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt
@@ -74,6 +74,8 @@
     val debuggable: Boolean
     val minSdk: AndroidVersion
 
+    val useBuiltInKotlinSupport: Boolean
+
     // ---------------------------------------------------------------------------------------------
     // OPTIONAL FEATURES
     // ---------------------------------------------------------------------------------------------
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt
index 7771136..8bc6b5a 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt
@@ -18,7 +18,6 @@
 
 import com.android.SdkConstants.FN_CLASSES_JAR
 import com.android.build.api.artifact.ScopedArtifact
-import com.android.build.api.instrumentation.FramesComputationMode
 import com.android.build.api.variant.ScopedArtifacts
 import com.android.build.gradle.internal.component.ComponentCreationConfig
 import com.android.build.gradle.internal.profile.ProfileAwareWorkAction
@@ -181,6 +180,9 @@
             } else {
                 task.inputDirs.from(
                     listOfNotNull(
+                        creationConfig.artifacts
+                            .get(InternalArtifactType.KOTLINC)
+                            .takeIf { creationConfig.useBuiltInKotlinSupport },
                         creationConfig.artifacts.get(InternalArtifactType.JAVAC),
                         creationConfig.oldVariantApiLegacySupport?.variantData?.allPreJavacGeneratedBytecode,
                         creationConfig.oldVariantApiLegacySupport?.variantData?.allPostJavacGeneratedBytecode
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/ModelBuilder.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/ModelBuilder.kt
index 52583b5..1688c62 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/ModelBuilder.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/ModelBuilder.kt
@@ -789,6 +789,11 @@
         component.androidResourcesCreationConfig?.compiledRClassArtifact?.get()?.asFile?.let {
             classesFolders.add(it)
         }
+        if (component.useBuiltInKotlinSupport) {
+            classesFolders.add(
+                component.artifacts.get(InternalArtifactType.KOTLINC).get().asFile
+            )
+        }
 
         val generatedClassPaths = addGeneratedClassPaths(component, classesFolders)
 
@@ -930,10 +935,13 @@
         // steps that create bytecode
         val classesFolders = mutableSetOf<File>()
         classesFolders.add(component.artifacts.get(InternalArtifactType.JAVAC).get().asFile)
-        component.oldVariantApiLegacySupport?.let{
+        component.oldVariantApiLegacySupport?.let {
             classesFolders.addAll(it.variantData.allPreJavacGeneratedBytecode.files)
             classesFolders.addAll(it.variantData.allPostJavacGeneratedBytecode.files)
         }
+        if (component.useBuiltInKotlinSupport) {
+            classesFolders.add(component.artifacts.get(InternalArtifactType.KOTLINC).get().asFile)
+        }
         // The separately compile R class, if applicable.
         if (extension.testOptions.unitTests.isIncludeAndroidResources ||
             component.componentType.isForScreenshotPreview) {
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt
index ef1aa89..f32f1ee 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt
@@ -1787,6 +1787,9 @@
                 )
             } else {
                 classesOutputDirectories.from(creationConfig.artifacts.get(InternalArtifactType.JAVAC))
+                if (creationConfig.useBuiltInKotlinSupport) {
+                    classesOutputDirectories.from(creationConfig.artifacts.get(InternalArtifactType.KOTLINC))
+                }
             }
             creationConfig.oldVariantApiLegacySupport?.variantData?.let {
                 classesOutputDirectories.from(
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt
index b204681..a982681 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt
@@ -41,6 +41,7 @@
 import com.android.build.gradle.internal.services.AndroidLocationsBuildService
 import com.android.build.gradle.internal.services.DslServices
 import com.android.build.gradle.internal.services.ProjectServices
+import com.android.build.gradle.internal.utils.MINIMUM_INTEGRATED_KOTLIN_VERSION
 import com.android.build.gradle.internal.utils.MUTUALLY_EXCLUSIVE_ANDROID_GRADLE_PLUGINS
 import com.android.build.gradle.options.BooleanOption
 import com.android.build.gradle.options.ProjectOptionService
@@ -56,6 +57,7 @@
 import org.gradle.api.configuration.BuildFeatures
 import org.gradle.api.tasks.StopExecutionException
 import org.gradle.build.event.BuildEventsListenerRegistry
+import org.jetbrains.kotlin.gradle.plugin.KotlinBaseApiPlugin
 import java.util.Locale
 
 abstract class AndroidPluginBaseServices(
@@ -138,6 +140,30 @@
             NoOpAnalyticsService.RegistrationAction(project).execute()
         }
 
+        if (projectOptions.get(BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT)
+            || projectOptions.get(BooleanOption.ENABLE_SCREENSHOT_TEST)) {
+            try {
+                project.plugins.apply(KotlinBaseApiPlugin::class.java)
+            } catch (e: Throwable) {
+                if (e is ClassNotFoundException || e is NoClassDefFoundError) {
+                    val message =
+                        """
+                            The Kotlin Gradle plugin was not found on the project's buildscript
+                            classpath. Add "org.jetbrains.kotlin:kotlin-gradle-plugin:$MINIMUM_INTEGRATED_KOTLIN_VERSION" to the
+                            buildscript classpath in order to use any of the following Gradle
+                            properties:
+
+                            ${BooleanOption.ENABLE_SCREENSHOT_TEST.propertyName},
+                            ${BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT.propertyName}
+
+                        """.trimIndent()
+                    syncIssueReporter.reportError(Type.GENERIC, message)
+                } else {
+                    throw e
+                }
+            }
+        }
+
         SyncIssueReporterImpl.GlobalSyncIssueService.RegistrationAction(
             project,
             SyncOptions.getModelQueryMode(projectOptions),
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/InternalArtifactType.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/InternalArtifactType.kt
index 65856ea..c682eda 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/InternalArtifactType.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/InternalArtifactType.kt
@@ -49,6 +49,8 @@
     // module: InternalArtifactType<RegularFile>(FILE), Replaceable use AnchorOutputType.ALL_CLASSES
     // Javac task output.
     object JAVAC: InternalArtifactType<Directory>(DIRECTORY), Replaceable
+    // Kotlin Built-in Support compile task output
+    object KOTLINC: InternalArtifactType<Directory>(DIRECTORY), Replaceable
 
     // --- Published classes ---
     // Class-type task output for tasks that generate published classes.
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/ProjectInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/ProjectInfo.kt
index 125aa70..50d1fc6 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/ProjectInfo.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/scope/ProjectInfo.kt
@@ -18,6 +18,7 @@
 
 import com.android.SdkConstants
 import com.android.builder.core.BuilderConstants
+import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.capabilities.Capability
 import org.gradle.api.file.Directory
@@ -99,6 +100,12 @@
 
     fun hasPlugin(plugin: String): Boolean = project.plugins.hasPlugin(plugin)
 
+    fun <T : Plugin<*>> hasPlugin(pluginClass: Class<T>): Boolean =
+        project.plugins.hasPlugin(pluginClass)
+
+    fun <T : Plugin<*>> findPlugin(pluginClass: Class<T>): T? =
+        project.plugins.findPlugin(pluginClass)
+
     @Deprecated("Use buildDirectory instead")
     fun getBuildDir(): File {
         return project.buildDir
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServices.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServices.kt
index 9bb6ead..e26f402 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServices.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServices.kt
@@ -19,9 +19,15 @@
 import com.android.build.gradle.internal.errors.DeprecationReporter
 import com.android.build.gradle.internal.scope.ProjectInfo
 import com.android.build.gradle.internal.utils.GradleEnvironmentProvider
+import com.android.build.gradle.internal.utils.MINIMUM_INTEGRATED_KOTLIN_VERSION
+import com.android.build.gradle.internal.utils.getKotlinPluginVersionFromPlugin
+import com.android.build.gradle.options.BooleanOption
 import com.android.build.gradle.options.ProjectOptions
 import com.android.builder.errors.IssueReporter
+import com.android.ide.common.gradle.Version
 import org.gradle.api.services.BuildServiceRegistry
+import org.jetbrains.kotlin.gradle.plugin.KotlinBaseApiPlugin
+import org.jetbrains.kotlin.gradle.plugin.KotlinJvmFactory
 import java.io.File
 
 /**
@@ -35,8 +41,44 @@
     val buildServiceRegistry: BuildServiceRegistry
     val gradleEnvironmentProvider: GradleEnvironmentProvider
     val projectInfo: ProjectInfo
+    val kotlinServices: KotlinServices?
 
     fun <T> newInstance(type: Class<T>, vararg args: Any?): T
 
     fun file(file: Any): File
 }
+
+interface KotlinServices {
+
+    val kgpVersion: String
+    val factory: KotlinJvmFactory
+
+    companion object {
+
+        fun createFromPlugin(plugin: KotlinBaseApiPlugin?): KotlinServices? {
+            plugin ?: return null
+            getKotlinPluginVersionFromPlugin(plugin)?.let {
+                if (Version.parse(it) < Version.parse(MINIMUM_INTEGRATED_KOTLIN_VERSION)) {
+                    val message =
+                        """
+                            The current Kotlin Gradle plugin version ($it) is below the required
+                            minimum version ($MINIMUM_INTEGRATED_KOTLIN_VERSION).
+
+                            The following Gradle properties require the Kotlin Gradle plugin version
+                            to be at least $MINIMUM_INTEGRATED_KOTLIN_VERSION:
+
+                            ${BooleanOption.ENABLE_SCREENSHOT_TEST.propertyName},
+                            ${BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT.propertyName}
+
+                        """.trimIndent()
+                    throw RuntimeException(message)
+                }
+            }
+
+            return object : KotlinServices {
+                override val kgpVersion: String = plugin.pluginVersion
+                override val factory: KotlinJvmFactory = plugin
+            }
+        }
+    }
+}
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServicesImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServicesImpl.kt
index 72ca90c..501d356 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServicesImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/BaseServicesImpl.kt
@@ -18,8 +18,10 @@
 
 import com.android.build.gradle.internal.errors.DeprecationReporter
 import com.android.build.gradle.internal.scope.ProjectInfo
+import com.android.build.gradle.internal.services.KotlinServices.Companion.createFromPlugin
 import com.android.build.gradle.internal.utils.GradleEnvironmentProvider
 import com.android.build.gradle.internal.utils.GradleEnvironmentProviderImpl
+import com.android.build.gradle.internal.utils.findKotlinBaseApiPlugin
 import com.android.build.gradle.options.ProjectOptions
 import com.android.builder.errors.IssueReporter
 import org.gradle.api.services.BuildServiceRegistry
@@ -49,4 +51,9 @@
 
     final override val projectInfo: ProjectInfo
         get() = projectServices.projectInfo
+
+    override val kotlinServices: KotlinServices? by lazy {
+        val kotlinBaseApiPlugin = findKotlinBaseApiPlugin(projectInfo) ?: return@lazy null
+        createFromPlugin(kotlinBaseApiPlugin)
+    }
 }
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfig.kt
index 1700695..e340f68 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfig.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfig.kt
@@ -45,6 +45,7 @@
 import org.gradle.api.file.Directory
 import org.gradle.api.file.FileCollection
 import org.gradle.api.provider.Provider
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
 
 /**
  * Creation config for global tasks that are not variant-based.
@@ -93,6 +94,8 @@
     val unitTestOptions: UnitTestOptionsDslInfo
     val testServers: List<TestServer>
 
+    val kotlinOptions: KotlinJvmOptions?
+
     // processed access to some DSL values
 
     val namespacedAndroidResources: Boolean
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfigImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfigImpl.kt
index e14e453..000fb6f 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfigImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/GlobalTaskCreationConfigImpl.kt
@@ -64,7 +64,9 @@
 import org.gradle.api.attributes.AttributeContainer
 import org.gradle.api.file.Directory
 import org.gradle.api.file.FileCollection
+import org.gradle.api.plugins.ExtensionAware
 import org.gradle.api.provider.Provider
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
 
 class GlobalTaskCreationConfigImpl(
     project: Project,
@@ -188,6 +190,9 @@
     override val testServers: List<TestServer>
         get() = oldExtension.testServers
 
+    override val kotlinOptions: KotlinJvmOptions?
+        get() = (oldExtension as ExtensionAware).extensions.findByName("kotlinOptions") as? KotlinJvmOptions
+
     override val namespacedAndroidResources: Boolean
         get() = extension.androidResources.namespaced
 
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/KmpGlobalTaskCreationConfigImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/KmpGlobalTaskCreationConfigImpl.kt
index 3fe6715..20b388b 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/KmpGlobalTaskCreationConfigImpl.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/factory/KmpGlobalTaskCreationConfigImpl.kt
@@ -64,6 +64,7 @@
 import org.gradle.api.file.Directory
 import org.gradle.api.file.FileCollection
 import org.gradle.api.provider.Provider
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
 
 internal class KmpGlobalTaskCreationConfigImpl(
     project: Project,
@@ -253,4 +254,6 @@
         get() = throw IllegalAccessException("Not supported for kmp")
     override val dataBinding: DataBinding
         get() = throw IllegalAccessException("Not supported for kmp")
+    override val kotlinOptions: KotlinJvmOptions
+        get() = throw IllegalAccessException("Not supported for kmp")
 }
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/kgpUtils.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/kgpUtils.kt
index 0a31a41..6ac4058 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/kgpUtils.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/kgpUtils.kt
@@ -24,17 +24,22 @@
 import com.android.build.gradle.internal.component.ComponentCreationConfig
 import com.android.build.gradle.internal.component.LibraryCreationConfig
 import com.android.build.gradle.internal.profile.AnalyticsConfiguratorService
+import com.android.build.gradle.internal.scope.ProjectInfo
 import com.android.build.gradle.internal.services.getBuildService
+import com.android.builder.errors.IssueReporter
 import com.android.utils.appendCapitalized
 import com.google.wireless.android.sdk.stats.GradleBuildVariant
 import org.gradle.api.NamedDomainObjectContainer
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier
+import org.gradle.api.artifacts.result.ResolvedDependencyResult
 import org.gradle.api.file.FileCollection
 import org.gradle.api.file.SourceDirectorySet
 import org.gradle.api.tasks.ClasspathNormalizer
 import org.gradle.api.tasks.SourceSet
+import org.jetbrains.kotlin.gradle.plugin.KotlinBaseApiPlugin
 import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
@@ -160,20 +165,19 @@
 /** Records information from KGP for analytics. */
 fun recordKgpPropertiesForAnalytics(project: Project, creationConfigs: List<ComponentCreationConfig>) {
     configureKotlinCompileTasks(project, creationConfigs) { kotlinCompile, creationConfig ->
-        recordKotlinCompilePropertiesForAnalytics(kotlinCompile, creationConfig, project)
+        recordKotlinCompilePropertiesForAnalytics(kotlinCompile, creationConfig)
     }
 }
 
-private fun recordKotlinCompilePropertiesForAnalytics(
+fun recordKotlinCompilePropertiesForAnalytics(
     kotlinCompile: KotlinCompile,
-    creationConfig: ComponentCreationConfig,
-    project: Project
+    creationConfig: ComponentCreationConfig
 ) {
     getLanguageVersionUnsafe(kotlinCompile)?.let { languageVersion ->
         getBuildService(
             creationConfig.services.buildServiceRegistry,
             AnalyticsConfiguratorService::class.java
-        ).get().getVariantBuilder(project.path, creationConfig.name)?.apply {
+        ).get().getVariantBuilder(creationConfig.services.projectInfo.path, creationConfig.name)?.apply {
             setKotlinOptions(
                 GradleBuildVariant.KotlinOptions.newBuilder().setLanguageVersion(languageVersion)
             )
@@ -322,3 +326,61 @@
         creationConfig.services.configurations.findByName(configurationName)
     }
 }
+
+fun isKotlinBaseApiPluginApplied(projectInfo: ProjectInfo): Boolean =
+    try {
+        projectInfo.hasPlugin(KotlinBaseApiPlugin::class.java)
+    } catch (e: Throwable) {
+        if (e is ClassNotFoundException || e is NoClassDefFoundError) false else throw e
+    }
+
+fun findKotlinBaseApiPlugin(projectInfo: ProjectInfo): KotlinBaseApiPlugin? =
+    try {
+        projectInfo.findPlugin(KotlinBaseApiPlugin::class.java)
+    } catch (e: Throwable) {
+        if (e is ClassNotFoundException || e is NoClassDefFoundError) null else throw e
+    }
+
+/**
+ * Check that the kotlin stdlib is present in the compile and runtime classpaths
+ *
+ * KGP automatically adds the kotlin stdlib dependency, which is not desirable behavior. Instead of
+ * doing that, AGP checks for the dependency when the "com.android.kotlin" plugin is applied and
+ * instructs users to add the dependency if it is missing.
+ */
+internal fun checkKotlinStdLibIsInDependencies(
+    project: Project,
+    creationConfig: ComponentCreationConfig
+) {
+    val defaultVersion = creationConfig.services.kotlinServices?.kgpVersion ?: return
+
+    // TODO(b/259523353): add DSL flag to ignore this check
+    fun Configuration.checkKotlinStdlibPresent() {
+        incoming.afterResolve {
+            val hasKotlinStdLib = it.resolutionResult.allDependencies
+                .filterIsInstance<ResolvedDependencyResult>()
+                .map { it.selected.id }
+                .filterIsInstance<ModuleComponentIdentifier>()
+                .any {
+                    it.group == KOTLIN_GROUP && (it.module == "kotlin-stdlib" || it.module == "kotlin-stdlib-jdk8")
+                }
+            if (!hasKotlinStdLib) {
+                creationConfig.services.issueReporter.reportError(
+                    IssueReporter.Type.GENERIC,
+                    """
+Kotlin standard library is missing from ${this.name}. Please add a dependency on
+"$KOTLIN_GROUP:kotlin-stdlib:$defaultVersion" to your build file: `${project.buildFile.toURI()}`
+                """.trimIndent()
+                )
+            }
+        }
+    }
+
+    creationConfig.variantDependencies.compileClasspath.checkKotlinStdlibPresent()
+    creationConfig.variantDependencies.runtimeClasspath.checkKotlinStdlibPresent()
+}
+
+private const val KOTLIN_GROUP = "org.jetbrains.kotlin"
+// The minimum version of KGP required to be on the buildscript classpath for integrated kotlin
+// support in AGP
+const val MINIMUM_INTEGRATED_KOTLIN_VERSION = "1.9.20"
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt
index c446e80..f6c7600 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt
@@ -306,6 +306,15 @@
         FeatureStage.Experimental
     ),
 
+    /**
+     * Whether to enable kotlin compilation for test fixtures
+     */
+    ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT(
+        "android.experimental.enableTestFixturesKotlinSupport",
+        false,
+        FeatureStage.Experimental
+    ),
+
     /* ------------------------
      * SOFTLY-ENFORCED FEATURES
      */
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/JavaCompileUtils.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/JavaCompileUtils.kt
index 4c38c96..f5ec8b5 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/JavaCompileUtils.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/JavaCompileUtils.kt
@@ -33,6 +33,7 @@
 import com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType.JAR
 import com.android.build.gradle.internal.publishing.AndroidArtifacts.ConsumedConfigType.ANNOTATION_PROCESSOR
 import com.android.build.gradle.internal.services.getBuildService
+import com.android.build.gradle.internal.scope.InternalArtifactType
 import com.android.build.gradle.options.BooleanOption
 import com.android.builder.errors.DefaultIssueReporter
 import com.android.builder.errors.IssueReporter
@@ -98,11 +99,19 @@
             // classes(e.g. android.jar) that were previously passed through bootstrapClasspath need to be provided
             // through classpath
             creationConfig.global.bootClasspath,
-            creationConfig.compileClasspath
+            creationConfig.compileClasspath,
+            creationConfig.artifacts
+                .get(InternalArtifactType.KOTLINC)
+                .takeIf { creationConfig.useBuiltInKotlinSupport },
         )
     } else {
         this.options.bootstrapClasspath = this.project.files(creationConfig.global.bootClasspath)
-        this.classpath = creationConfig.compileClasspath
+        this.classpath = project.files(
+            creationConfig.compileClasspath,
+            creationConfig.artifacts
+                .get(InternalArtifactType.KOTLINC)
+                .takeIf { creationConfig.useBuiltInKotlinSupport },
+        )
     }
 
     this.sourceCompatibility = compileOptions.sourceCompatibility.toString()
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/KotlinCompileCreationAction.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/KotlinCompileCreationAction.kt
new file mode 100644
index 0000000..e6561a5
--- /dev/null
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/KotlinCompileCreationAction.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 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 com.android.build.gradle.tasks
+
+import com.android.build.gradle.internal.component.ComponentCreationConfig
+import com.android.build.gradle.internal.component.NestedComponentCreationConfig
+import com.android.build.gradle.internal.profile.PROPERTY_VARIANT_NAME_KEY
+import com.android.build.gradle.internal.publishing.AndroidArtifacts
+import com.android.build.gradle.internal.publishing.PublishingSpecs
+import com.android.build.gradle.internal.scope.InternalArtifactType
+import com.android.build.gradle.internal.scope.MutableTaskContainer
+import org.gradle.api.tasks.TaskProvider
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
+import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
+
+class KotlinCompileCreationAction(private val creationConfig: ComponentCreationConfig) {
+
+    val taskName: String = creationConfig.computeTaskNameInternal("compile", "Kotlin")
+
+    private fun getTaskFactory(): TaskProvider<out KotlinJvmCompile> {
+        return creationConfig.services
+            .kotlinServices!!
+            .factory
+            .registerKotlinJvmCompileTask(
+                taskName,
+                creationConfig.name
+            )
+    }
+
+    private fun handleProvider(task: TaskProvider<out KotlinJvmCompile>) {
+        val artifacts = creationConfig.artifacts
+        artifacts.setInitialProvider(task) { it.destinationDirectory }
+            .withName("classes")
+            .on(InternalArtifactType.KOTLINC)
+    }
+
+    private fun configureTask(task: KotlinJvmCompile) {
+        creationConfig.sources.kotlin {
+            task.source(it.getAsFileTrees())
+        }
+        creationConfig.sources.java {
+            task.source(it.getAsFileTrees())
+        }
+
+        val taskClasspath =
+            creationConfig.services.fileCollection().from(
+                creationConfig.getJavaClasspath(
+                    AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH,
+                    AndroidArtifacts.ArtifactType.CLASSES_JAR,
+                    null
+                ),
+                creationConfig.global.bootClasspath
+            )
+        task.libraries.setFrom(taskClasspath)
+
+        task.sourceSetName.set(creationConfig.name)
+        task.useModuleDetection.set(true)
+        task.multiPlatformEnabled.set(false)
+
+        task.pluginClasspath
+            .from(creationConfig.services.kotlinServices!!.factory.getCompilerPlugins())
+        // TODO(b/259523353) - fix this
+        // task.pluginOptions.addAll(creationConfig.kotlinCompilerOptions!!)
+
+        // Add friendPaths to allow access to internal properties of main variant
+        if (creationConfig is NestedComponentCreationConfig) {
+            val mainVariant = creationConfig.mainVariant
+            val internalArtifactType =
+                PublishingSpecs.getVariantPublishingSpec(mainVariant.componentType)
+                    .getSpec(
+                        AndroidArtifacts.ArtifactType.CLASSES_JAR,
+                        AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH.publishedTo
+                    )
+                    ?.outputType
+            internalArtifactType?.let {
+                task.friendPaths.from(
+                    creationConfig.services.fileCollection(mainVariant.artifacts.get(it))
+                )
+            }
+        }
+
+        creationConfig.global.kotlinOptions?.let { task.applyJvmOptions(it) }
+    }
+
+    fun registerTask() {
+        val taskProvider = getTaskFactory()
+        handleProvider(taskProvider)
+
+        taskProvider.configure {
+            val taskContainer: MutableTaskContainer = creationConfig.taskContainer
+            it.dependsOn(taskContainer.preBuildTask)
+            it.extensions.add(PROPERTY_VARIANT_NAME_KEY, creationConfig.name)
+
+            configureTask(it)
+        }
+    }
+}
+
+private fun KotlinJvmCompile.applyJvmOptions(options: KotlinJvmOptions) {
+    kotlinOptions {
+        // TODO(b/259523353): Initialize task options from the DSL object, add API in KGP for
+        //  automatic copying
+        jvmTarget = options.jvmTarget
+        javaParameters = options.javaParameters
+        moduleName = options.moduleName
+        noJdk = options.noJdk
+
+        apiVersion = options.apiVersion
+        languageVersion = options.languageVersion
+        useK2 = options.useK2
+
+        freeCompilerArgs = options.freeCompilerArgs
+        allWarningsAsErrors = options.allWarningsAsErrors
+        suppressWarnings = options.suppressWarnings
+        verbose = options.verbose
+    }
+}
diff --git a/build-system/integration-test/application/BUILD.bazel b/build-system/integration-test/application/BUILD.bazel
index d558d8e..90c7482 100644
--- a/build-system/integration-test/application/BUILD.bazel
+++ b/build-system/integration-test/application/BUILD.bazel
@@ -1,5 +1,5 @@
 load("//tools/base/bazel:maven.bzl", "maven_repository")
-load("//tools/base/build-system/integration-test:common-dependencies.bzl", "KGP_VERSION_FOR_TESTS")
+load("//tools/base/build-system/integration-test:common-dependencies.bzl", "KGP_VERSION_FOR_TESTS", "KGP_1_9_22", "KGP_1_8_10")
 load("//tools/base/build-system/integration-test:integration-test.bzl", "gradle_integration_test", "single_gradle_integration_test_per_source")
 load("//tools/base/build-system/integration-test:integration-test.bzl", "single_gradle_integration_test")
 
@@ -159,6 +159,7 @@
     "//tools/base/build-system/integration-test:test-projects/sourceDependency",
     "//tools/base/build-system/integration-test:test-projects/testDependency",
     "//tools/base/build-system/integration-test:test-projects/testFixturesApp",
+    "//tools/base/build-system/integration-test:test-projects/testFixturesKotlinApp",
     "//tools/base/build-system/integration-test:test-projects/testWithDep",
     "//tools/base/build-system/integration-test:test-projects/tictactoe",
     "//tools/base/build-system/integration-test:test-projects/transformApiTest",
@@ -249,6 +250,7 @@
         exclude = SOURCES_TO_COMPILE_TOGETHER + CONNECTED_TESTS + CHECK_ALL_SOURCES + [
             # These subpackages have their own target definitions.
             "src/test/java/com/android/build/gradle/integration/packaging/**",
+            "src/test/java/com/android/build/gradle/integration/kotlin/**",
             "src/test/java/com/android/build/gradle/integration/library/**",
             "src/test/java/com/android/build/gradle/integration/mlkit/**",
             "src/test/java/com/android/build/gradle/integration/testing/**",
@@ -417,6 +419,44 @@
     deps = TEST_DEPS,
 )
 
+maven_repository(
+    name = "kotlin_1_8_10",
+    artifacts = KGP_1_8_10,
+    visibility = [":__subpackages__"],
+)
+
+maven_repository(
+    name = "kotlin_1_9_22",
+    artifacts = KGP_1_9_22,
+    visibility = [":__subpackages__"],
+)
+
+gradle_integration_test(
+    name = "built-in-kotlin-support-tests",
+    srcs = glob(
+        [
+            "src/test/java/com/android/build/gradle/integration/kotlin/*.java",
+            "src/test/java/com/android/build/gradle/integration/kotlin/*.kt",
+        ],
+    ),
+    data = TEST_DATA,
+    maven_repo_zips = [
+        "//tools/base/build-system:android_gradle_plugin",
+    ],
+    maven_repos = [
+        "//tools/base/build-system:android_gradle_plugin_runtime_dependencies",
+        "//tools/base/build-system/integration-test:androidx_latest",
+        "//tools/base/build-system/integration-test:support_library_latest",
+        "//tools/base/build-system/integration-test:kotlin_gradle_plugin_prebuilts",
+        "//tools/base/build-system/integration-test/application:kotlin_1_8_10",
+        "//tools/base/build-system/integration-test/application:kotlin_1_9_22",
+        "//tools/base/build-system/integration-test/application:prebuilts",
+    ],
+    resources = glob(["src/test/resources/**"]),
+    shard_count = 2,
+    deps = TEST_DEPS,
+)
+
 gradle_integration_test(
     name = "dependencies-tests",
     timeout = "long",
diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ComposeHelloWorldTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ComposeHelloWorldTest.kt
index 144401f..b3ec034 100644
--- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ComposeHelloWorldTest.kt
+++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ComposeHelloWorldTest.kt
@@ -18,6 +18,7 @@
 
 import com.android.build.gradle.integration.common.fixture.GradleTestProject
 import com.android.build.gradle.integration.common.utils.TestFileUtils
+import com.android.testutils.truth.PathSubject.assertThat
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -54,4 +55,37 @@
         val result = project.executor().run("assembleDebug")
         assertThat(result.didWorkTasks).contains(":app:compileDebugKotlin")
     }
+
+    @Test
+    fun testScreenshotTestAndTestFixturesCompilation() {
+        project.executor().run(":app:compileDebugTestFixturesKotlin")
+        val testFixturesClassFile =
+            project.getSubproject("app")
+                .getIntermediateFile(
+                    "kotlinc",
+                    "debugTestFixtures",
+                    "compileDebugTestFixturesKotlin",
+                    "classes",
+                    "com",
+                    "example",
+                    "helloworldcompose",
+                    "FixtureKt.class"
+                )
+        assertThat(testFixturesClassFile).exists()
+
+        project.executor().run(":app:compileDebugScreenshotTestKotlin")
+        val screenshotTestClassFile =
+            project.getSubproject("app")
+                .getIntermediateFile(
+                    "kotlinc",
+                    "debugScreenshotTest",
+                    "compileDebugScreenshotTestKotlin",
+                    "classes",
+                    "com",
+                    "example",
+                    "helloworldcompose",
+                    "ScreenshotTestKt.class"
+                )
+        assertThat(screenshotTestClassFile).exists()
+    }
 }
diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/BuiltInKotlinSupportTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/BuiltInKotlinSupportTest.kt
new file mode 100644
index 0000000..dfaab79
--- /dev/null
+++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/BuiltInKotlinSupportTest.kt
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.gradle.integration.kotlin
+
+import com.android.build.gradle.integration.common.fixture.GradleTestProject.Companion.VERSION_CATALOG
+import com.android.build.gradle.integration.common.fixture.testprojects.PluginType
+import com.android.build.gradle.integration.common.fixture.testprojects.createGradleProjectBuilder
+import com.android.build.gradle.integration.common.fixture.testprojects.prebuilts.setUpHelloWorld
+import com.android.build.gradle.integration.common.truth.TruthHelper.assertThat
+import com.android.build.gradle.integration.common.utils.TestFileUtils
+import com.android.build.gradle.internal.dsl.ModulePropertyKey.BooleanWithDefault.SCREENSHOT_TEST
+import com.android.build.gradle.options.BooleanOption
+import com.android.testutils.TestUtils
+import com.android.testutils.apk.Aar
+import com.android.testutils.truth.PathSubject
+import org.junit.Rule
+import org.junit.Test
+
+class BuiltInKotlinSupportTest {
+
+    @get:Rule
+    val project =
+        createGradleProjectBuilder {
+            subProject(":lib") {
+                plugins.add(PluginType.ANDROID_LIB)
+                plugins.add(PluginType.KOTLIN_ANDROID)
+                android {
+                    setUpHelloWorld()
+                }
+            }
+        }.withKotlinGradlePlugin(true)
+            .create()
+
+    @Test
+    fun testTestFixturesKotlinSupport() {
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.testFixtures.enable = true
+
+                kotlin {
+                    jvmToolchain(17)
+                }
+
+                dependencies {
+                    testFixturesImplementation("org.jetbrains.kotlin:kotlin-stdlib:${TestUtils.KOTLIN_VERSION_FOR_TESTS}")
+                }
+                """.trimIndent()
+        )
+        lib.file("src/testFixtures/kotlin/LibTestFixtureFoo.kt").let {
+            it.parentFile.mkdirs()
+            it.writeText(
+                """
+                    package com.foo.library
+                    class LibTestFixtureFoo
+                    """.trimIndent()
+            )
+        }
+        lib.executor().run(":lib:assembleDebugTestFixtures")
+        val aar = lib.outputDir.resolve("aar").listFiles().single()
+        Aar(aar).use {
+            assertThat(it).containsMainClass("Lcom/foo/library/LibTestFixtureFoo;")
+        }
+    }
+
+    @Test
+    fun testScreenshotTest() {
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_SCREENSHOT_TEST.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.experimentalProperties["${SCREENSHOT_TEST.key}"] = true
+
+                kotlin {
+                    jvmToolchain(17)
+                }
+
+                dependencies {
+                    testFixturesImplementation("org.jetbrains.kotlin:kotlin-stdlib:${TestUtils.KOTLIN_VERSION_FOR_TESTS}")
+                }
+                """.trimIndent()
+        )
+        lib.file("src/screenshotTest/kotlin/LibScreenshotTest.kt").let {
+            it.parentFile.mkdirs()
+            it.writeText(
+                """
+                    package com.foo.library
+                    class LibScreenshotTest
+                    """.trimIndent()
+            )
+        }
+        lib.executor().run(":lib:compileDebugScreenshotTestKotlin")
+        val screenshotTestClassFile =
+            project.getSubproject("lib")
+                .getIntermediateFile(
+                    "kotlinc",
+                    "debugScreenshotTest",
+                    "compileDebugScreenshotTestKotlin",
+                    "classes",
+                    "com",
+                    "foo",
+                    "library",
+                    "LibScreenshotTest.class"
+                )
+        PathSubject.assertThat(screenshotTestClassFile).exists()
+    }
+
+    @Test
+    fun testInternalModifierAccessibleFromTestFixtures() {
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.testFixtures.enable = true
+
+                kotlin {
+                    jvmToolchain(17)
+                }
+
+                dependencies {
+                    testFixturesImplementation("org.jetbrains.kotlin:kotlin-stdlib:${TestUtils.KOTLIN_VERSION_FOR_TESTS}")
+                }
+                """.trimIndent()
+        )
+        lib.file("src/testFixtures/kotlin/LibTestFixtureFoo.kt").let {
+            it.parentFile.mkdirs()
+            it.writeText(
+                """
+                    package com.foo.library
+                    class LibTestFixtureFoo {
+                      init { LibFoo().bar() }
+                    }
+                    """.trimIndent()
+            )
+        }
+        lib.getMainSrcDir("java").resolve("LibFoo.kt").let {
+            it.parentFile.mkdirs()
+            it.writeText(
+                """
+                    package com.foo.library
+                    class LibFoo {
+                      internal fun bar() {}
+                    }
+                """.trimIndent()
+            )
+        }
+        lib.executor().run(":lib:assembleDebugTestFixtures")
+    }
+
+    @Test
+    fun testInternalModifierAccessibleFromScreenshotTest() {
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_SCREENSHOT_TEST.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.experimentalProperties["${SCREENSHOT_TEST.key}"] = true
+
+                kotlin {
+                    jvmToolchain(17)
+                }
+
+                dependencies {
+                    testFixturesImplementation("org.jetbrains.kotlin:kotlin-stdlib:${TestUtils.KOTLIN_VERSION_FOR_TESTS}")
+                }
+                """.trimIndent()
+        )
+        lib.file("src/screenshotTest/kotlin/LibScreenshotTestFoo.kt").let {
+            it.parentFile.mkdirs()
+            it.writeText(
+                """
+                    package com.foo.library
+                    class LibScreenshotTestFoo {
+                      init { LibFoo().bar() }
+                    }
+                    """.trimIndent()
+            )
+        }
+        lib.getMainSrcDir("java").resolve("LibFoo.kt").let {
+            it.parentFile.mkdirs()
+            it.writeText(
+                """
+                    package com.foo.library
+                    class LibFoo {
+                      internal fun bar() {}
+                    }
+                """.trimIndent()
+            )
+        }
+        lib.executor().run(":lib:compileDebugScreenshotTestKotlin")
+    }
+
+    @Test
+    fun testLowKotlinVersionWithTestFixturesKotlinSupport() {
+        TestFileUtils.searchAndReplace(
+            project.projectDir.parentFile.resolve(VERSION_CATALOG),
+            "version('kotlinVersion', '${TestUtils.KOTLIN_VERSION_FOR_TESTS}')",
+            "version('kotlinVersion', '1.8.10')"
+        )
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_TEST_FIXTURES_KOTLIN_SUPPORT.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.testFixtures.enable = true
+
+                kotlin {
+                    jvmToolchain(17)
+                }
+
+                dependencies {
+                    testFixturesImplementation("org.jetbrains.kotlin:kotlin-stdlib:${TestUtils.KOTLIN_VERSION_FOR_TESTS}")
+                }
+                """.trimIndent()
+        )
+        val result = lib.executor().expectFailure().run(":lib:assembleDebugTestFixtures")
+        result.assertErrorContains(
+            "The current Kotlin Gradle plugin version (1.8.10) is below the required"
+        )
+    }
+
+    @Test
+    fun testLowKotlinVersionWithScreenshotTest() {
+        TestFileUtils.searchAndReplace(
+            project.projectDir.parentFile.resolve(VERSION_CATALOG),
+            "version('kotlinVersion', '${TestUtils.KOTLIN_VERSION_FOR_TESTS}')",
+            "version('kotlinVersion', '1.8.10')"
+        )
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_SCREENSHOT_TEST.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.experimentalProperties["${SCREENSHOT_TEST.key}"] = true
+
+                kotlin {
+                    jvmToolchain(17)
+                }
+
+                dependencies {
+                    testFixturesImplementation("org.jetbrains.kotlin:kotlin-stdlib:${TestUtils.KOTLIN_VERSION_FOR_TESTS}")
+                }
+                """.trimIndent()
+        )
+        val result = lib.executor().expectFailure().run(":lib:compileDebugScreenshotTest")
+        result.assertErrorContains(
+            "The current Kotlin Gradle plugin version (1.8.10) is below the required"
+        )
+    }
+
+    @Test
+    fun testLowKotlinVersionWithNoBuiltInKotlinSupport() {
+        TestFileUtils.searchAndReplace(
+            project.projectDir.parentFile.resolve(VERSION_CATALOG),
+            "version('kotlinVersion', '${TestUtils.KOTLIN_VERSION_FOR_TESTS}')",
+            "version('kotlinVersion', '1.8.10')"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.testFixtures.enable = true
+                """.trimIndent()
+        )
+        // We expect no build failure in this case.
+        // Set failOnWarning to false because Gradle warns about deprecated feature(s) used by KGP 1.8.10.
+        lib.executor().withFailOnWarning(false).run(":lib:assembleDebugTestFixtures")
+    }
+}
diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/BuiltInKotlinSupportWithoutKgpTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/BuiltInKotlinSupportWithoutKgpTest.kt
new file mode 100644
index 0000000..fcb52ef
--- /dev/null
+++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/BuiltInKotlinSupportWithoutKgpTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.gradle.integration.kotlin
+
+import com.android.build.gradle.integration.common.fixture.testprojects.PluginType
+import com.android.build.gradle.integration.common.fixture.testprojects.createGradleProjectBuilder
+import com.android.build.gradle.integration.common.fixture.testprojects.prebuilts.setUpHelloWorld
+import com.android.build.gradle.integration.common.utils.TestFileUtils
+import com.android.build.gradle.internal.dsl.ModulePropertyKey.BooleanWithDefault.SCREENSHOT_TEST
+import com.android.build.gradle.options.BooleanOption
+import org.junit.Rule
+import org.junit.Test
+
+class BuiltInKotlinSupportWithoutKgpTest {
+
+    @get:Rule
+    val project =
+        createGradleProjectBuilder {
+            subProject(":lib") {
+                plugins.add(PluginType.ANDROID_LIB)
+                android {
+                    setUpHelloWorld()
+                }
+            }
+        }.create()
+
+    @Test
+    fun testKgpMissingFromClasspath() {
+        TestFileUtils.appendToFile(
+            project.gradlePropertiesFile,
+            "${BooleanOption.ENABLE_SCREENSHOT_TEST.propertyName}=true"
+        )
+        val lib = project.getSubproject(":lib")
+        lib.buildFile.appendText(
+            """
+                android.experimentalProperties["${SCREENSHOT_TEST.key}"] = true
+                """.trimIndent()
+        )
+        val result = lib.executor().expectFailure().run(":lib:assembleDebug")
+        result.assertErrorContains("The Kotlin Gradle plugin was not found")
+    }
+}
diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/TestFixturesKotlinTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/TestFixturesKotlinTest.kt
new file mode 100644
index 0000000..0463cdf
--- /dev/null
+++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/kotlin/TestFixturesKotlinTest.kt
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2024 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 com.android.build.gradle.integration.kotlin
+
+import com.android.build.gradle.integration.common.fixture.GradleTestProject
+import com.android.build.gradle.integration.common.fixture.GradleTestProject.Companion.VERSION_CATALOG
+import com.android.build.gradle.integration.common.utils.TestFileUtils
+import com.android.testutils.TestUtils
+import com.android.testutils.apk.Apk
+import com.android.testutils.truth.PathSubject.assertThat
+import com.google.common.truth.Truth
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.io.File
+
+/**
+ * Similar to [TestFixturesTest], but using a project with kotlin test fixtures
+ */
+@RunWith(Parameterized::class)
+class TestFixturesKotlinTest(private val kotlinVersion: String) {
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "kotlinVersion_{0}")
+        fun parameters() = listOf(TestUtils.KOTLIN_VERSION_FOR_TESTS, "1.9.22")
+    }
+
+    @get:Rule
+    val project: GradleTestProject =
+        GradleTestProject.builder().fromTestProject("testFixturesKotlinApp").create()
+
+    @Before
+    fun before() {
+        TestFileUtils.searchAndReplace(
+            project.projectDir.parentFile.resolve(VERSION_CATALOG),
+            "version('kotlinVersion', '${TestUtils.KOTLIN_VERSION_FOR_TESTS}')",
+            "version('kotlinVersion', '$kotlinVersion' )"
+        )
+    }
+
+    private fun setUpProject(publishJavaLib: Boolean, publishAndroidLib: Boolean) {
+        if (publishJavaLib) {
+            TestFileUtils.searchAndReplace(
+                project.getSubproject(":app").buildFile,
+                "project(\":javaLib\")",
+                "'com.example.javaLib:javaLib:1.0'"
+            )
+
+            TestFileUtils.searchAndReplace(
+                project.getSubproject(":appTests").buildFile,
+                "project(\":javaLib\")",
+                "'com.example.javaLib:javaLib:1.0'"
+            )
+        }
+
+
+        if (publishAndroidLib) {
+            TestFileUtils.searchAndReplace(
+                project.getSubproject(":app").buildFile,
+                "project(\":lib\")",
+                "'com.example.lib:lib:1.0'"
+            )
+
+            TestFileUtils.searchAndReplace(
+                project.getSubproject(":lib2").buildFile,
+                "project(\":lib\")",
+                "'com.example.lib:lib:1.0'"
+            )
+
+            TestFileUtils.searchAndReplace(
+                project.getSubproject(":appTests").buildFile,
+                "project(\":lib\")",
+                "'com.example.lib:lib:1.0'"
+            )
+        }
+
+        if (publishJavaLib) {
+            TestFileUtils.appendToFile(project.getSubproject(":javaLib").buildFile,
+                """
+                publishing {
+                    repositories {
+                        maven {
+                            url = uri("../testrepo")
+                        }
+                    }
+                    publications {
+                        release(MavenPublication) {
+                            from components.java
+                            groupId = 'com.example.javaLib'
+                            artifactId = 'javaLib'
+                            version = '1.0'
+                        }
+                    }
+                }
+
+                // required for testFixtures publishing
+                group = 'com.example.javaLib'
+            """.trimIndent()
+            )
+        }
+
+        if (publishAndroidLib) {
+            TestFileUtils.appendToFile(project.getSubproject(":lib").buildFile,
+                """
+                android {
+                    publishing {
+                        singleVariant("release")
+                    }
+                }
+
+                afterEvaluate {
+                    publishing {
+                        repositories {
+                            maven {
+                                url = uri("../testrepo")
+                            }
+                        }
+                        publications {
+                            release(MavenPublication) {
+                                from components.release
+                                groupId = 'com.example.lib'
+                                artifactId = 'lib'
+                                version = '1.0'
+                            }
+                        }
+                    }
+                }
+
+                // required for testFixtures publishing
+                group = 'com.example.lib'
+            """.trimIndent()
+            )
+        }
+
+        if (publishJavaLib) {
+            project.executor()
+                .run(":javaLib:publish")
+        }
+
+        if (publishAndroidLib) {
+            project.executor()
+                .run(":lib:publish")
+        }
+    }
+
+    @Test
+    fun `library consumes local test fixtures`() {
+        project.executor()
+            .run(":lib:testDebugUnitTest")
+    }
+
+    @Test
+    fun `verify library test fixtures resources dependency on main resources`() {
+        project.executor()
+            .run(":lib:verifyReleaseTestFixturesResources")
+    }
+
+    @Test
+    fun `verify library resources dependency on test fixtures resources from local project`() {
+        setUpProject(
+            publishJavaLib = false,
+            publishAndroidLib = false
+        )
+        project.executor()
+            .run(":lib2:verifyReleaseResources")
+    }
+
+    @Test
+    fun `verify library resources dependency on test fixtures resources from published lib`() {
+        setUpProject(
+            publishJavaLib = false,
+            publishAndroidLib = true
+        )
+        project.executor()
+            .run(":lib2:verifyReleaseResources")
+    }
+
+    @Test
+    fun `verify library test dependency on test fixtures resources from local project`() {
+        setUpProject(
+            publishJavaLib = false,
+            publishAndroidLib = false
+        )
+        project.executor()
+            .run(":lib2:testDebugUnitTest")
+    }
+
+    @Test
+    fun `verify library test dependency on test fixtures resources from published lib`() {
+        setUpProject(
+            publishJavaLib = false,
+            publishAndroidLib = true
+        )
+        project.executor()
+            .run(":lib2:testDebugUnitTest")
+    }
+
+    @Test
+    fun `app consumes local, java and android library test fixtures`() {
+        setUpProject(
+            publishJavaLib = false,
+            publishAndroidLib = false
+        )
+        project.executor()
+            .run(":app:testDebugUnitTest")
+    }
+
+    @Test
+    fun `app consumes local, published java and android library test fixtures`() {
+        setUpProject(
+            publishJavaLib = true,
+            publishAndroidLib = true
+        )
+        project.executor()
+            .run(":app:testDebugUnitTest")
+    }
+
+    @Test
+    fun `app consumes android library test fixtures published using new publishing dsl`() {
+        setUpProject(
+            publishJavaLib = false,
+            publishAndroidLib = true
+        )
+        project.executor()
+            .run(":app:testDebugUnitTest")
+    }
+
+    @Test
+    fun `publish android library main variant without its test fixtures`() {
+        TestFileUtils.appendToFile(
+            project.getSubproject(":lib").buildFile,
+            """
+
+                afterEvaluate {
+                    components.release.withVariantsFromConfiguration(
+                        configurations.releaseTestFixturesVariantReleaseApiPublication) { skip() }
+                    components.release.withVariantsFromConfiguration(
+                        configurations.releaseTestFixturesVariantReleaseRuntimePublication) { skip() }
+                }
+
+            """.trimIndent()
+        )
+        setUpProject(
+            publishAndroidLib = true,
+            publishJavaLib = true
+        )
+        val testFixtureAar = "testrepo/com/example/lib/lib/1.0/lib-1.0-test-fixtures.aar"
+        val mainVariantAar = "testrepo/com/example/lib/lib/1.0/lib-1.0.aar"
+        assertThat(project.projectDir.resolve(testFixtureAar)).doesNotExist()
+        assertThat(project.projectDir.resolve(mainVariantAar)).exists()
+    }
+
+    @Test
+    fun `lint analyzes local and library module testFixtures sources`() {
+        setUpProjectForLint(
+            ignoreTestFixturesSourcesInApp = false
+        )
+        setUpProject(
+            publishAndroidLib = false,
+            publishJavaLib = false
+        )
+        project.executor().run(":app:lintRelease")
+        val reportFile = File(project.getSubproject("app").projectDir, "lint-results.txt")
+        assertThat(reportFile).exists()
+        assertThat(reportFile).containsAllOf(
+            "AppInterfaceTester.kt:21: Error: STOPSHIP comment found;",
+            "LibResourcesTester.java:35: Error: Missing permissions required by LibResourcesTester.methodWithUnavailablePermission: android.permission.ACCESS_COARSE_LOCATION [MissingPermission]"
+        )
+    }
+
+    @Test
+    fun `lint ignores local testFixtures sources`() {
+        setUpProjectForLint(
+            ignoreTestFixturesSourcesInApp = true
+        )
+        setUpProject(
+            publishAndroidLib = false,
+            publishJavaLib = false
+        )
+        project.executor().run(":app:lintRelease")
+        val reportFile = File(project.getSubproject("app").projectDir, "lint-results.txt")
+        assertThat(reportFile).exists()
+        assertThat(reportFile).containsAllOf(
+            "LibResourcesTester.java:35: Error: Missing permissions required by LibResourcesTester.methodWithUnavailablePermission: android.permission.ACCESS_COARSE_LOCATION [MissingPermission]"
+        )
+    }
+
+    @Test
+    fun `test plugin consumes test fixtures`() {
+        setUpProject(
+            publishAndroidLib = false,
+            publishJavaLib = false
+        )
+        useAndroidX()
+
+        project.executor().run(":appTests:packageDebug")
+
+        testExclusionInTestApk(
+            testApk = project.getSubproject(":appTests").getApk(GradleTestProject.ApkType.DEBUG),
+            expectLibAndJavaLibClassesToBeIncluded = true,
+        )
+    }
+
+    @Test
+    fun `test plugin consumes published test fixtures`() {
+        setUpProject(
+            publishAndroidLib = true,
+            publishJavaLib = true
+        )
+        useAndroidX()
+
+        project.executor().run(":appTests:packageDebug")
+
+        testExclusionInTestApk(
+            testApk = project.getSubproject(":appTests").getApk(GradleTestProject.ApkType.DEBUG),
+            expectLibAndJavaLibClassesToBeIncluded = true,
+        )
+    }
+
+    @Test
+    fun `test plugin excludes main lib classes but includes test fixtures`() {
+        setUpProject(
+            publishAndroidLib = false,
+            publishJavaLib = false
+        )
+        useAndroidX()
+
+        TestFileUtils.searchAndReplace(
+            project.getSubproject(":app").buildFile,
+            "compileOnly",
+            "implementation"
+        )
+
+        project.executor().run(":appTests:packageDebug")
+
+        testExclusionInTestApk(
+            testApk = project.getSubproject(":appTests").getApk(GradleTestProject.ApkType.DEBUG),
+            expectLibAndJavaLibClassesToBeIncluded = false,
+        )
+    }
+
+    @Test
+    fun `instrumentation tests consume test fixtures`() {
+        setUpProject(
+            publishAndroidLib = false,
+            publishJavaLib = false
+        )
+        useAndroidX()
+
+        project.executor().run(":app:packageDebugAndroidTest")
+
+        testExclusionInTestApk(
+            testApk = project.getSubproject(":app").getApk(GradleTestProject.ApkType.ANDROIDTEST_DEBUG),
+            expectLibAndJavaLibClassesToBeIncluded = true,
+        )
+    }
+
+    @Test
+    fun `instrumentation tests consume published test fixtures`() {
+        setUpProject(
+            publishAndroidLib = true,
+            publishJavaLib = true
+        )
+        useAndroidX()
+
+        project.executor().run(":app:packageDebugAndroidTest")
+
+        testExclusionInTestApk(
+            testApk = project.getSubproject(":app").getApk(GradleTestProject.ApkType.ANDROIDTEST_DEBUG),
+            expectLibAndJavaLibClassesToBeIncluded = true,
+        )
+    }
+
+    @Test
+    fun `instrumentation tests exclude main lib classes but include test fixtures`() {
+        setUpProject(
+            publishAndroidLib = false,
+            publishJavaLib = false
+        )
+        useAndroidX()
+
+        TestFileUtils.searchAndReplace(
+            project.getSubproject(":app").buildFile,
+            "compileOnly",
+            "implementation"
+        )
+
+        project.executor().run(":app:packageDebugAndroidTest")
+
+        testExclusionInTestApk(
+            testApk = project.getSubproject(":app").getApk(GradleTestProject.ApkType.ANDROIDTEST_DEBUG),
+            expectLibAndJavaLibClassesToBeIncluded = false,
+        )
+    }
+
+    @Test
+    fun `test kotlin stdlib missing`() {
+        TestFileUtils.searchAndReplace(
+            project.getSubproject(":app").buildFile,
+            "testFixturesImplementation \"org.jetbrains.kotlin:kotlin-stdlib:\${libs.versions.kotlinVersion.get()}\"",
+            ""
+        )
+        val result = project.executor().expectFailure().run(":app:testDebugUnitTest")
+        result.assertErrorContains("Kotlin standard library is missing")
+    }
+
+    @Test
+    fun `test kotlin version too low`() {
+        Assume.assumeTrue(kotlinVersion == TestUtils.KOTLIN_VERSION_FOR_TESTS)
+        TestFileUtils.searchAndReplace(
+            project.projectDir.parentFile.resolve(VERSION_CATALOG),
+            "version('kotlinVersion', '$kotlinVersion' )",
+            "version('kotlinVersion', '1.8.10' )"
+        )
+        val result = project.executor().expectFailure().run(":app:testDebugUnitTest")
+        result.assertErrorContains(
+            "The current Kotlin Gradle plugin version (1.8.10) is below the required"
+        )
+    }
+
+    private fun testExclusionInTestApk(
+        testApk: Apk,
+        expectTestFixturesClassesToBeIncluded: Boolean = true,
+        expectLibAndJavaLibClassesToBeIncluded: Boolean,
+        expectAppClassesToBeIncluded: Boolean = false
+    ) {
+        testApk.use {
+            it.mainDexFile.get().classes.keys.let { classes ->
+                // test fixtures classes
+                listOf(
+                    "Lcom/example/app/testFixtures/AppInterfaceTester;",
+                    "Lcom/example/javalib/testFixtures/JavaLibInterfaceTester;",
+                    "Lcom/example/lib/testFixtures/LibInterfaceTester;",
+                    "Lcom/example/lib/testFixtures/LibResourcesTester;"
+                ).forEach { clazz ->
+                    if (expectTestFixturesClassesToBeIncluded) {
+                        Truth.assertThat(classes).contains(clazz)
+                    } else {
+                        Truth.assertThat(classes).doesNotContain(clazz)
+                    }
+                }
+
+                // lib and java lib classes
+                listOf(
+                    "Lcom/example/javalib/JavaLibInterface;",
+                    "Lcom/example/lib/LibInterface;",
+                ).forEach { clazz ->
+                    if (expectLibAndJavaLibClassesToBeIncluded) {
+                        Truth.assertThat(classes).contains(clazz)
+                    } else {
+                        Truth.assertThat(classes).doesNotContain(clazz)
+                    }
+                }
+
+                // app classes
+                listOf(
+                    "Lcom/example/app/AppInterface;"
+                ).forEach { clazz ->
+                    if (expectAppClassesToBeIncluded) {
+                        Truth.assertThat(classes).contains(clazz)
+                    } else {
+                        Truth.assertThat(classes).doesNotContain(clazz)
+                    }
+                }
+            }
+        }
+    }
+
+    private fun setUpProjectForLint(ignoreTestFixturesSourcesInApp: Boolean) {
+        project.getSubproject(":app").buildFile.appendText(
+            """
+                android {
+                    testBuildType "release"
+                    lint {
+                        abortOnError false
+                        enable 'StopShip'
+                        textOutput file("lint-results.txt")
+                        checkDependencies true
+                        ignoreTestFixturesSources $ignoreTestFixturesSourcesInApp
+                    }
+                }
+            """.trimIndent()
+        )
+        TestFileUtils.searchAndReplace(
+            project.getSubproject(":app")
+                .file("src/testFixtures/java/com/example/app/testFixtures/AppInterfaceTester.kt"),
+            "class AppInterfaceTester(private val name: String) {",
+            "// STOPSHIP\n" + "class AppInterfaceTester(private val name: String) {"
+        )
+        project.getSubproject(":lib").buildFile.appendText(
+            """
+                android {
+                    testBuildType "release"
+                }
+
+                dependencies {
+                    testFixturesApi 'androidx.annotation:annotation:1.1.0'
+                }
+            """.trimIndent()
+        )
+        TestFileUtils.searchAndReplace(
+            project.getSubproject(":lib")
+                .file("src/testFixtures/java/com/example/lib/testFixtures/LibResourcesTester.java"),
+            "public void test() {",
+            """
+                @androidx.annotation.RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+                public void methodWithUnavailablePermission() {
+                }
+
+                public void test() {
+                    methodWithUnavailablePermission();
+            """.trimIndent()
+        )
+        useAndroidX()
+    }
+
+    private fun useAndroidX() {
+        TestFileUtils.appendToFile(project.file("gradle.properties"), "android.useAndroidX=true")
+    }
+}
diff --git a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleTestProject.kt b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleTestProject.kt
index 7be5de6..e936da6 100644
--- a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleTestProject.kt
+++ b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleTestProject.kt
@@ -162,7 +162,7 @@
         internal const val COMMON_LOCAL_REPO = "commonLocalRepo.gradle"
         private const val COMMON_BUILD_SCRIPT = "commonBuildScript.gradle"
         private const val COMMON_VERSIONS = "commonVersions.gradle"
-        private const val VERSION_CATALOG = "versionCatalog.gradle"
+        const val VERSION_CATALOG = "versionCatalog.gradle"
         const val DEFAULT_TEST_PROJECT_NAME = "project"
 
         @JvmStatic
diff --git a/build-system/integration-test/test-projects/composeHelloWorld/app/build.gradle b/build-system/integration-test/test-projects/composeHelloWorld/app/build.gradle
index 8796163..06366ec 100644
--- a/build-system/integration-test/test-projects/composeHelloWorld/app/build.gradle
+++ b/build-system/integration-test/test-projects/composeHelloWorld/app/build.gradle
@@ -35,6 +35,10 @@
     composeOptions {
         kotlinCompilerExtensionVersion = "${libs.versions.composeCompilerVersion.get()}"
     }
+    testFixtures {
+        enable = true
+    }
+    experimentalProperties["android.experimental.enableScreenshotTest"] = true
 }
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
@@ -51,4 +55,10 @@
     androidTestImplementation 'androidx.test.ext:junit:1.1.3-alpha02'
     androidTestImplementation 'androidx.test:rules:1.4.0-alpha06'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+    testFixturesImplementation "org.jetbrains.kotlin:kotlin-stdlib:${libs.versions.kotlinVersionForCompose.get()}"
+    testFixturesImplementation "androidx.activity:activity-compose:1.5.1"
+    testFixturesImplementation "androidx.compose.ui:ui:${libs.versions.composeVersion.get()}"
+    testFixturesImplementation "androidx.compose.material:material:${libs.versions.composeVersion.get()}"
+    testFixturesImplementation "androidx.compose.ui:ui-tooling:${libs.versions.composeVersion.get()}"
 }
diff --git a/build-system/integration-test/test-projects/composeHelloWorld/app/src/screenshotTest/java/com/example/helloworldcompose/ScreenshotTest.kt b/build-system/integration-test/test-projects/composeHelloWorld/app/src/screenshotTest/java/com/example/helloworldcompose/ScreenshotTest.kt
new file mode 100644
index 0000000..26dbfac
--- /dev/null
+++ b/build-system/integration-test/test-projects/composeHelloWorld/app/src/screenshotTest/java/com/example/helloworldcompose/ScreenshotTest.kt
@@ -0,0 +1,24 @@
+package com.example.helloworldcompose
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun HelloWorldColumn() {
+    Column(modifier = Modifier.padding(16.dp)) {
+        Text("Hello, World1")
+        Text("Hello, World2")
+        Text("Hello, World3")
+    }
+}
+
+@Preview
+@Composable
+fun PreviewGreeting() {
+    HelloWorldColumn()
+}
diff --git a/build-system/integration-test/test-projects/composeHelloWorld/app/src/testFixtures/java/com/example/helloworldcompose/Fixture.kt b/build-system/integration-test/test-projects/composeHelloWorld/app/src/testFixtures/java/com/example/helloworldcompose/Fixture.kt
new file mode 100644
index 0000000..26dbfac
--- /dev/null
+++ b/build-system/integration-test/test-projects/composeHelloWorld/app/src/testFixtures/java/com/example/helloworldcompose/Fixture.kt
@@ -0,0 +1,24 @@
+package com.example.helloworldcompose
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun HelloWorldColumn() {
+    Column(modifier = Modifier.padding(16.dp)) {
+        Text("Hello, World1")
+        Text("Hello, World2")
+        Text("Hello, World3")
+    }
+}
+
+@Preview
+@Composable
+fun PreviewGreeting() {
+    HelloWorldColumn()
+}
diff --git a/build-system/integration-test/test-projects/composeHelloWorld/gradle.properties b/build-system/integration-test/test-projects/composeHelloWorld/gradle.properties
index 6ce64b0..767fc7d 100644
--- a/build-system/integration-test/test-projects/composeHelloWorld/gradle.properties
+++ b/build-system/integration-test/test-projects/composeHelloWorld/gradle.properties
@@ -14,4 +14,6 @@
 # limitations under the License.
 #
 
-android.useAndroidX=true
\ No newline at end of file
+android.useAndroidX=true
+android.experimental.enableScreenshotTest=true
+android.experimental.enableTestFixturesKotlinSupport=true
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/build.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/build.gradle
new file mode 100644
index 0000000..48f330e
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/build.gradle
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+plugins {
+    id 'com.android.application'
+    id 'kotlin-android'
+}
+
+android {
+    namespace "com.example.app"
+    compileSdkVersion libs.versions.latestCompileSdk.get().toInteger()
+    buildToolsVersion = libs.versions.buildToolsVersion.get()
+
+    defaultConfig {
+        minSdkVersion libs.versions.supportLibMinSdk.get()
+    }
+
+    lintOptions {
+        checkReleaseBuilds false
+    }
+
+    testFixtures.enable = true
+}
+
+kotlin {
+    jvmToolchain(17)
+}
+
+dependencies {
+    compileOnly project(":javaLib")
+    compileOnly project(":lib")
+
+    testFixturesApi 'com.google.truth:truth:0.44'
+    testFixturesImplementation "org.jetbrains.kotlin:kotlin-stdlib:${libs.versions.kotlinVersion.get()}"
+
+    testImplementation 'junit:junit:4.12'
+    testImplementation testFixtures(project(":javaLib"))
+    testImplementation testFixtures(project(":lib"))
+
+    androidTestImplementation testFixtures(project(":javaLib"))
+    androidTestImplementation testFixtures(project(":lib"))
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/AndroidManifest.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5c3d365
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest/>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/AppInterface.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/AppInterface.kt
new file mode 100644
index 0000000..7837fdc
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/AppInterface.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 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 com.example.app
+
+interface AppInterface {
+    val name: String?
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/JavaLibInterfaceImpl.java b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/JavaLibInterfaceImpl.java
new file mode 100644
index 0000000..1908301
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/JavaLibInterfaceImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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 com.example.app;
+
+import com.example.javalib.JavaLibInterface;
+
+public class JavaLibInterfaceImpl implements JavaLibInterface {
+    private int id;
+
+    public JavaLibInterfaceImpl(int id) {
+        this.id = id;
+    }
+
+    @Override
+    public int getId() {
+        return id;
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/LibInterfaceImpl.java b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/LibInterfaceImpl.java
new file mode 100644
index 0000000..ecb22b5
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/main/java/com/example/app/LibInterfaceImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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 com.example.app;
+
+import com.example.lib.LibInterface;
+
+public class LibInterfaceImpl implements LibInterface {
+    private String name;
+
+    public LibInterfaceImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/test/java/com/example/test/UnitTest.java b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/test/java/com/example/test/UnitTest.java
new file mode 100644
index 0000000..c18cfcf
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/test/java/com/example/test/UnitTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 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 com.example.test;
+
+import com.example.app.AppInterface;
+import com.example.app.JavaLibInterfaceImpl;
+import com.example.app.LibInterfaceImpl;
+import com.example.app.testFixtures.AppInterfaceTester;
+import com.example.javalib.testFixtures.JavaLibInterfaceTester;
+import com.example.lib.testFixtures.LibInterfaceTester;
+import org.junit.Test;
+
+public class UnitTest {
+
+    @Test
+    public void testAndroidLibTestFixturesDependency() {
+        String name = "test";
+        LibInterfaceTester tester = new LibInterfaceTester(name);
+        tester.test(new LibInterfaceImpl(name));
+    }
+
+    @Test
+    public void testJavaLibTestFixturesDependency() {
+        int id = 1234;
+        JavaLibInterfaceTester tester = new JavaLibInterfaceTester(id);
+        tester.test(new JavaLibInterfaceImpl(id));
+    }
+
+    @Test
+    public void testLocalAppTestFixturesDependency() {
+        AppInterfaceTester tester = new AppInterfaceTester("test");
+        tester.test(new AppInterfaceImpl());
+    }
+
+    private class AppInterfaceImpl implements AppInterface {
+        @Override
+        public String getName() {
+            return "test";
+        }
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/test/java/com/example/test/UnitTestKotlin.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/test/java/com/example/test/UnitTestKotlin.kt
new file mode 100644
index 0000000..ea97285
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/test/java/com/example/test/UnitTestKotlin.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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 com.example.test
+
+import com.example.app.AppInterface
+import com.example.app.JavaLibInterfaceImpl
+import com.example.app.LibInterfaceImpl
+import com.example.app.testFixtures.AppInterfaceTester
+import com.example.javalib.testFixtures.JavaLibInterfaceTester
+import com.example.lib.testFixtures.LibInterfaceTester
+import org.junit.Test
+
+class UnitTestKotlin {
+    @Test
+    fun testAndroidLibTestFixturesDependency() {
+        val name = "test"
+        val tester: LibInterfaceTester = LibInterfaceTester(name)
+        tester.test(LibInterfaceImpl(name))
+    }
+
+    @Test
+    fun testJavaLibTestFixturesDependency() {
+        val id = 1234
+        val tester: JavaLibInterfaceTester = JavaLibInterfaceTester(id)
+        tester.test(JavaLibInterfaceImpl(id))
+    }
+
+    @Test
+    fun testLocalAppTestFixturesDependency() {
+        val tester: AppInterfaceTester = AppInterfaceTester("test")
+        tester.test(AppInterfaceImpl())
+    }
+
+    private inner class AppInterfaceImpl : AppInterface {
+        override val name = "test"
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/testFixtures/java/com/example/app/testFixtures/AppInterfaceTester.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/testFixtures/java/com/example/app/testFixtures/AppInterfaceTester.kt
new file mode 100644
index 0000000..e5ac1c8
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/app/src/testFixtures/java/com/example/app/testFixtures/AppInterfaceTester.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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 com.example.app.testFixtures
+
+import com.example.app.AppInterface
+import com.google.common.truth.Truth
+
+class AppInterfaceTester(private val name: String) {
+    fun test(`object`: AppInterface) {
+        Truth.assertThat(`object`.name).isEqualTo(name)
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/appTests/build.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/appTests/build.gradle
new file mode 100644
index 0000000..456cb2b
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/appTests/build.gradle
@@ -0,0 +1,24 @@
+plugins {
+    id 'com.android.test'
+}
+
+android {
+    namespace = "com.example.apptests"
+    compileSdkVersion libs.versions.latestCompileSdk.get().toInteger()
+    buildToolsVersion = libs.versions.buildToolsVersion.get()
+
+    targetProjectPath ':app'
+
+    defaultConfig {
+        minSdkVersion libs.versions.supportLibMinSdk.get()
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+}
+
+dependencies {
+    implementation testFixtures(project(":app"))
+    implementation testFixtures(project(":javaLib"))
+    implementation testFixtures(project(":lib"))
+
+    implementation 'junit:junit:4.12'
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/appTests/src/main/AndroidManifest.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/appTests/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5c3d365
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/appTests/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest/>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/build.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/build.gradle
new file mode 100644
index 0000000..583a331
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/build.gradle
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+apply from: "../commonHeader.gradle"
+buildscript {
+    apply from: "../commonHeader.gradle"  // for $kotlinVersion
+    apply from: "../commonBuildScript.gradle"
+
+    dependencies {
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlinVersion.get()}"
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/gradle.properties b/build-system/integration-test/test-projects/testFixturesKotlinApp/gradle.properties
new file mode 100644
index 0000000..0e3ef84
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/gradle.properties
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2024 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.
+#
+
+android.experimental.enableTestFixturesKotlinSupport=true
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/build.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/build.gradle
new file mode 100644
index 0000000..da7c6a7
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/build.gradle
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+plugins {
+    id 'java-library'
+    id 'java-test-fixtures'
+    id 'maven-publish'
+    id 'kotlin'
+}
+
+dependencies {
+    testFixturesApi 'com.google.truth:truth:0.44'
+}
+
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/src/main/java/com/example/javalib/JavaLibInterface.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/src/main/java/com/example/javalib/JavaLibInterface.kt
new file mode 100644
index 0000000..ab57295
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/src/main/java/com/example/javalib/JavaLibInterface.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 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 com.example.javalib
+
+interface JavaLibInterface {
+    val id: Int
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/src/testFixtures/java/com/example/javalib/testFixtures/JavaLibInterfaceTester.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/src/testFixtures/java/com/example/javalib/testFixtures/JavaLibInterfaceTester.kt
new file mode 100644
index 0000000..435fb0e
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/javaLib/src/testFixtures/java/com/example/javalib/testFixtures/JavaLibInterfaceTester.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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 com.example.javalib.testFixtures
+
+import com.example.javalib.JavaLibInterface
+import com.google.common.truth.Truth
+
+class JavaLibInterfaceTester(private val id: Int) {
+    fun test(`object`: JavaLibInterface) {
+        Truth.assertThat(`object`.id).isEqualTo(id)
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/build.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/build.gradle
new file mode 100644
index 0000000..a11cdd6
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+plugins {
+    id 'com.android.library'
+    id 'maven-publish'
+    id 'kotlin-android'
+}
+
+android {
+    namespace "com.example.lib"
+    compileSdkVersion libs.versions.latestCompileSdk.get().toInteger()
+    testFixtures {
+        enable true
+        androidResources true
+    }
+}
+
+kotlin {
+    jvmToolchain(17)
+}
+
+dependencies {
+    testFixturesApi 'com.google.truth:truth:0.44'
+    testFixturesImplementation "org.jetbrains.kotlin:kotlin-stdlib:${libs.versions.kotlinVersion.get()}"
+    testImplementation 'junit:junit:4.12'
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/AndroidManifest.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5c3d365
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest/>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/java/com/example/lib/LibInterface.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/java/com/example/lib/LibInterface.kt
new file mode 100644
index 0000000..3339510
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/java/com/example/lib/LibInterface.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 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 com.example.lib
+
+interface LibInterface {
+    val name: String?
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/res/values/strings.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/res/values/strings.xml
new file mode 100644
index 0000000..340f38f
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="libResourceString">lib resource string</string>
+</resources>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/test/java/com/example/test/UnitTest.java b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/test/java/com/example/test/UnitTest.java
new file mode 100644
index 0000000..e08659c
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/test/java/com/example/test/UnitTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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 com.example.test;
+
+import com.example.lib.LibInterface;
+import com.example.lib.testFixtures.LibInterfaceTester;
+import com.example.lib.testFixtures.LibResourcesTester;
+import org.junit.Test;
+
+public class UnitTest {
+    private class LibInterfaceImpl implements LibInterface {
+        @Override
+        public String getName() {
+            return "test";
+        }
+    }
+
+    @Test
+    public void testLibInterfaceTester() {
+        LibInterfaceTester tester = new LibInterfaceTester("test");
+        tester.test(new LibInterfaceImpl());
+    }
+
+    @Test
+    public void testLibResourcesTester() {
+        LibResourcesTester tester =
+                new LibResourcesTester(
+                        com.example.lib.R.string.libResourceString,
+                        com.example.lib.testFixtures.R.string.testFixturesResourceString);
+        tester.test();
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/test/java/com/example/test/UnitTestKotlin.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/test/java/com/example/test/UnitTestKotlin.kt
new file mode 100644
index 0000000..4d784b1
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/test/java/com/example/test/UnitTestKotlin.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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 com.example.test
+
+import com.example.lib.LibInterface
+import com.example.lib.testFixtures.LibInterfaceTester
+import com.example.lib.testFixtures.LibResourcesTester
+import org.junit.Test
+
+class UnitTestKotlin {
+    private inner class LibInterfaceImpl : LibInterface {
+        override val name = "test"
+    }
+
+    @Test
+    fun testLibInterfaceTester() {
+        val tester: LibInterfaceTester = LibInterfaceTester("test")
+        tester.test(LibInterfaceImpl())
+    }
+
+    @Test
+    fun testLibResourcesTester() {
+        val tester: LibResourcesTester =
+            LibResourcesTester(
+                com.example.lib.R.string.libResourceString,
+                com.example.lib.testFixtures.R.string.testFixturesResourceString
+            )
+        tester.test()
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/java/com/example/lib/testFixtures/LibInterfaceTester.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/java/com/example/lib/testFixtures/LibInterfaceTester.kt
new file mode 100644
index 0000000..0b17012
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/java/com/example/lib/testFixtures/LibInterfaceTester.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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 com.example.lib.testFixtures
+
+import com.example.lib.LibInterface
+import com.google.common.truth.Truth
+
+class LibInterfaceTester(private val name: String) {
+    fun test(`object`: LibInterface) {
+        Truth.assertThat(`object`.name).isEqualTo(name)
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/java/com/example/lib/testFixtures/LibResourcesTester.java b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/java/com/example/lib/testFixtures/LibResourcesTester.java
new file mode 100644
index 0000000..97c15e0
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/java/com/example/lib/testFixtures/LibResourcesTester.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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 com.example.lib.testFixtures;
+
+import com.google.common.truth.Truth;
+
+public class LibResourcesTester {
+    private int libResourceId;
+    private int testFixturesResourceId;
+
+    public LibResourcesTester(int libResourceId, int testFixturesResourceId) {
+        this.libResourceId = libResourceId;
+        this.testFixturesResourceId = testFixturesResourceId;
+    }
+
+    public void test() {
+        Truth.assertThat(com.example.lib.R.string.libResourceString).isEqualTo(this.libResourceId);
+        Truth.assertThat(com.example.lib.testFixtures.R.string.testFixturesResourceString)
+                .isEqualTo(this.testFixturesResourceId);
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/res/values/strings.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/res/values/strings.xml
new file mode 100644
index 0000000..8caab62
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib/src/testFixtures/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="testFixturesResourceString">@string/libResourceString</string>
+</resources>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/build.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/build.gradle
new file mode 100644
index 0000000..ecab548
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/build.gradle
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+plugins {
+    id 'com.android.library'
+    id 'kotlin-android'
+}
+
+android {
+    namespace "com.example.lib2"
+    compileSdkVersion libs.versions.latestCompileSdk.get().toInteger()
+}
+
+kotlin {
+    jvmToolchain(17)
+}
+
+dependencies {
+    implementation testFixtures(project(":lib"))
+
+    testImplementation 'junit:junit:4.12'
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/main/AndroidManifest.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5c3d365
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest/>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/main/res/values/strings.xml b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6df44c7
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/main/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<resources>
+    <string name="referenceToLibResourceString">@string/libResourceString</string>
+    <string name="referenceToTestFixturesResourceString">@string/testFixturesResourceString</string>
+</resources>
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/test/java/com/example/test/UnitTest.java b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/test/java/com/example/test/UnitTest.java
new file mode 100644
index 0000000..b20ee5f
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/test/java/com/example/test/UnitTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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 com.example.test;
+
+import com.example.lib.testFixtures.LibResourcesTester;
+import org.junit.Test;
+
+public class UnitTest {
+
+    @Test
+    public void testTestFixturesResourcesDependency() {
+        LibResourcesTester tester =
+                new LibResourcesTester(
+                        com.example.lib.R.string.libResourceString,
+                        com.example.lib.testFixtures.R.string.testFixturesResourceString);
+        tester.test();
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/test/java/com/example/test/UnitTestKotlin.kt b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/test/java/com/example/test/UnitTestKotlin.kt
new file mode 100644
index 0000000..c84de65
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/lib2/src/test/java/com/example/test/UnitTestKotlin.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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 com.example.test
+
+import com.example.lib.testFixtures.LibResourcesTester
+import org.junit.Test
+
+class UnitTestKotlin {
+    @Test
+    fun testTestFixturesResourcesDependency() {
+        val tester: LibResourcesTester =
+            LibResourcesTester(
+                com.example.lib.R.string.libResourceString,
+                com.example.lib.testFixtures.R.string.testFixturesResourceString
+            )
+        tester.test()
+    }
+}
diff --git a/build-system/integration-test/test-projects/testFixturesKotlinApp/settings.gradle b/build-system/integration-test/test-projects/testFixturesKotlinApp/settings.gradle
new file mode 100644
index 0000000..5dacde2
--- /dev/null
+++ b/build-system/integration-test/test-projects/testFixturesKotlinApp/settings.gradle
@@ -0,0 +1,13 @@
+include ':app'
+include ':appTests'
+include ':lib'
+include ':lib2'
+include ':javaLib'
+
+dependencyResolutionManagement {
+    repositories {
+        maven {
+            url = 'testrepo'
+        }
+    }
+}