Merge "[GH] Add workflow to create update prebuilts PR" into androidx-main
diff --git a/appsearch/compiler/build.gradle b/appsearch/compiler/build.gradle
index 274830c..f5a982c 100644
--- a/appsearch/compiler/build.gradle
+++ b/appsearch/compiler/build.gradle
@@ -31,7 +31,11 @@
 
     // For testing, add in the compiled classes from appsearch to get access to annotations.
     testImplementation fileTree(
-            dir: "${new File(project(":appsearch:appsearch").buildDir, "libJar")}",
+            dir: provider {
+                // Wrapping in a provider as a workaround as we access buildDir before this project is configured
+                // Replace with AGP API once it is added b/228109260
+                "${new File(project(":appsearch:appsearch").buildDir, "libJar")}"
+            },
             include : "*.jar"
     )
     testImplementation(libs.googleCompileTesting)
diff --git a/build.gradle b/build.gradle
index 99a5690..3a6b8e5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -23,7 +23,5 @@
 }
 
 apply from: "buildSrc/dependencies.gradle"
-apply from: "buildSrc/out.gradle"
-init.chooseOutDir()
 
 apply plugin: AndroidXRootPlugin
diff --git a/buildSrc/out.gradle b/buildSrc/out.gradle
index be42e80..0ca9069 100644
--- a/buildSrc/out.gradle
+++ b/buildSrc/out.gradle
@@ -14,25 +14,34 @@
  * limitations under the License.
  */
 
+import groovy.lang.Tuple;
+
 def init = new Properties()
 ext.init = init
 
-def chooseOutDir(subdir = "") {
+def getOutDir(subdir = "") {
     /*
      * The OUT_DIR is a temporary directory you can use to put things during the build.
      */
     def outDir = System.env.OUT_DIR
+    def buildSrcOut
     if (outDir == null) {
         def checkoutRoot = System.getProperty("CHECKOUT_ROOT")
         if (checkoutRoot == null) {
             checkoutRoot = new File("${buildscript.sourceFile.parent}/../../..")
         }
         outDir = new File("${checkoutRoot}/out${subdir}")
-        project.ext.buildSrcOut = new File("${checkoutRoot}/out/buildSrc")
+        buildSrcOut = new File("${checkoutRoot}/out/buildSrc")
     } else {
         outDir = new File(outDir)
-        project.ext.buildSrcOut = new File("${outDir}/buildSrc")
+        buildSrcOut = new File("${outDir}/buildSrc")
     }
+    return new Tuple(outDir, buildSrcOut)
+}
+
+def chooseOutDir(subdir = "") {
+    def (outDir, buildSrcOut) = getOutDir(subdir)
+    project.ext.buildSrcOut = buildSrcOut
     project.ext.outDir = outDir
     buildDir = new File(outDir, "$project.name/build")
                 .getCanonicalFile()
@@ -42,4 +51,5 @@
     }
 }
 
+ext.init.getOutDir = this.&getOutDir
 ext.init.chooseOutDir = this.&chooseOutDir
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 313ebd5..3d02e80 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2909,6 +2909,11 @@
     method public static void setVerticalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
   }
 
+  public final class SemanticsProperties_androidKt {
+    method public static boolean getTestTagsAsResourceId(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static void setTestTagsAsResourceId(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
+  }
+
   public final class SemanticsPropertyKey<T> {
     ctor public SemanticsPropertyKey(String name, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends T> mergePolicy);
     method public String getName();
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 80371fa..270ad0a 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -3041,6 +3041,12 @@
     field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
   }
 
+  @androidx.compose.ui.ExperimentalComposeUiApi public final class SemanticsPropertiesAndroid {
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getTestTagsAsResourceId();
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> TestTagsAsResourceId;
+    field public static final androidx.compose.ui.semantics.SemanticsPropertiesAndroid INSTANCE;
+  }
+
   public final class SemanticsPropertiesKt {
     method public static void collapse(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
     method public static void copyText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, optional String? label, kotlin.jvm.functions.Function0<java.lang.Boolean>? action);
@@ -3106,6 +3112,11 @@
     method public static void setVerticalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
   }
 
+  public final class SemanticsProperties_androidKt {
+    method public static boolean getTestTagsAsResourceId(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static void setTestTagsAsResourceId(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
+  }
+
   public final class SemanticsPropertyKey<T> {
     ctor public SemanticsPropertyKey(String name, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends T> mergePolicy);
     method public String getName();
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 652aaa7..424d6d5 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2945,6 +2945,11 @@
     method public static void setVerticalScrollAxisRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.ScrollAxisRange);
   }
 
+  public final class SemanticsProperties_androidKt {
+    method public static boolean getTestTagsAsResourceId(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static void setTestTagsAsResourceId(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean);
+  }
+
   public final class SemanticsPropertyKey<T> {
     ctor public SemanticsPropertyKey(String name, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends T> mergePolicy);
     method public String getName();
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index 2d750c5..41ef6e3 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -100,6 +100,7 @@
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.semantics.testTagsAsResourceId
 import androidx.compose.ui.semantics.textSelectionRange
 import androidx.compose.ui.test.SemanticsMatcher
 import androidx.compose.ui.test.TestActivity
@@ -2281,6 +2282,79 @@
     }
 
     @Test
+    @OptIn(ExperimentalComposeUiApi::class)
+    fun testTestTagsAsResourceId() {
+        val tag1 = "box1"
+        val tag2 = "box2"
+        val tag3 = "box3"
+        val tag4 = "box4"
+        val tag5 = "box5"
+        val tag6 = "box6"
+        val tag7 = "box7"
+        container.setContent {
+            with(LocalDensity.current) {
+                Column {
+                    Box(Modifier.size(100.toDp()).testTag(tag1))
+                    Box(Modifier.semantics { testTagsAsResourceId = true }) {
+                        Box(Modifier.size(100.toDp()).testTag(tag2))
+                    }
+                    Box(Modifier.semantics { testTagsAsResourceId = false }) {
+                        Box(Modifier.size(100.toDp()).testTag(tag3))
+                    }
+                    Box(Modifier.semantics { testTagsAsResourceId = true }) {
+                        Box(Modifier.semantics { testTagsAsResourceId = false }) {
+                            Box(Modifier.size(100.toDp()).testTag(tag4))
+                        }
+                    }
+                    Box(Modifier.semantics { testTagsAsResourceId = false }) {
+                        Box(Modifier.semantics { testTagsAsResourceId = true }) {
+                            Box(Modifier.size(100.toDp()).testTag(tag5))
+                        }
+                    }
+                    Box(Modifier.semantics(true) { testTagsAsResourceId = true }) {
+                        Box(Modifier.semantics { testTagsAsResourceId = false }) {
+                            Box(Modifier.size(100.toDp()).testTag(tag6))
+                        }
+                    }
+                    Box(Modifier.semantics(true) { testTagsAsResourceId = false }) {
+                        Box(Modifier.semantics { testTagsAsResourceId = true }) {
+                            Box(Modifier.size(100.toDp()).testTag(tag7))
+                        }
+                    }
+                }
+            }
+        }
+
+        val node1 = rule.onNodeWithTag(tag1).fetchSemanticsNode()
+        val info1 = provider.createAccessibilityNodeInfo(node1.id)!!
+        assertEquals(null, info1.viewIdResourceName)
+
+        val node2 = rule.onNodeWithTag(tag2).fetchSemanticsNode()
+        val info2 = provider.createAccessibilityNodeInfo(node2.id)!!
+        assertEquals(tag2, info2.viewIdResourceName)
+
+        val node3 = rule.onNodeWithTag(tag3).fetchSemanticsNode()
+        val info3 = provider.createAccessibilityNodeInfo(node3.id)!!
+        assertEquals(null, info3.viewIdResourceName)
+
+        val node4 = rule.onNodeWithTag(tag4).fetchSemanticsNode()
+        val info4 = provider.createAccessibilityNodeInfo(node4.id)!!
+        assertEquals(null, info4.viewIdResourceName)
+
+        val node5 = rule.onNodeWithTag(tag5).fetchSemanticsNode()
+        val info5 = provider.createAccessibilityNodeInfo(node5.id)!!
+        assertEquals(tag5, info5.viewIdResourceName)
+
+        val node6 = rule.onNodeWithTag(tag6, true).fetchSemanticsNode()
+        val info6 = provider.createAccessibilityNodeInfo(node6.id)!!
+        assertEquals(null, info6.viewIdResourceName)
+
+        val node7 = rule.onNodeWithTag(tag7, true).fetchSemanticsNode()
+        val info7 = provider.createAccessibilityNodeInfo(node7.id)!!
+        assertEquals(tag7, info7.viewIdResourceName)
+    }
+
+    @Test
     fun testContentDescription_notMergingDescendants_withOwnContentDescription() {
         val tag = "Column"
         container.setContent {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
index ccc4db7..e90f33a 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
@@ -72,6 +72,8 @@
 import androidx.compose.ui.semantics.setSelection
 import androidx.compose.ui.semantics.setText
 import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.semantics.testTag
+import androidx.compose.ui.semantics.testTagsAsResourceId
 import androidx.compose.ui.semantics.textSelectionRange
 import androidx.compose.ui.semantics.verticalScrollAxisRange
 import androidx.compose.ui.test.TestActivity
@@ -143,14 +145,18 @@
     }
 
     @Test
+    @OptIn(ExperimentalComposeUiApi::class)
     fun testPopulateAccessibilityNodeInfoProperties_general() {
         val clickActionLabel = "click"
         val dismissActionLabel = "dismiss"
         val expandActionLabel = "expand"
         val collapseActionLabel = "collapse"
         val stateDescription = "checked"
+        val resourceName = "myResourceName"
         val semanticsNode = createSemanticsNodeWithProperties(1, true) {
             this.stateDescription = stateDescription
+            testTag = resourceName
+            testTagsAsResourceId = true
             heading()
             onClick(clickActionLabel) { true }
             dismiss(dismissActionLabel) { true }
@@ -209,6 +215,7 @@
             }
         }
         assertEquals(stateDescription, stateDescriptionResult)
+        assertEquals(resourceName, info.viewIdResourceName)
         assertTrue(info.isHeading)
         assertTrue(info.isClickable)
         assertTrue(info.isVisibleToUser)
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index 0b65a0a..411334c 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -68,6 +68,7 @@
 import androidx.compose.ui.semantics.SemanticsNode
 import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.SemanticsPropertiesAndroid
 import androidx.compose.ui.semantics.SemanticsEntity
 import androidx.compose.ui.semantics.getOrNull
 import androidx.compose.ui.semantics.outerSemantics
@@ -514,6 +515,29 @@
             info.isScreenReaderFocusable = true
         }
 
+        // Map testTag to resourceName if testTagsAsResourceId == true (which can be set by an ancestor)
+        val testTag = semanticsNode.unmergedConfig.getOrNull(SemanticsProperties.TestTag)
+        if (testTag != null) {
+            var testTagsAsResourceId = false
+            var current: SemanticsNode? = semanticsNode
+            while (current != null) {
+                if (current.unmergedConfig.contains(
+                    SemanticsPropertiesAndroid.TestTagsAsResourceId
+                )) {
+                    testTagsAsResourceId = current.unmergedConfig.get(
+                        SemanticsPropertiesAndroid.TestTagsAsResourceId
+                    )
+                    break
+                } else {
+                    current = current.parent
+                }
+            }
+
+            if (testTagsAsResourceId) {
+                info.viewIdResourceName = testTag
+            }
+        }
+
         semanticsNode.unmergedConfig.getOrNull(SemanticsProperties.Heading)?.let {
             info.isHeading = true
         }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.android.kt
new file mode 100644
index 0000000..8726f63
--- /dev/null
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.android.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.semantics
+
+import androidx.compose.ui.ExperimentalComposeUiApi
+
+@ExperimentalComposeUiApi
+object SemanticsPropertiesAndroid {
+    /**
+     * @see SemanticsPropertyReceiver.testTagsAsResourceId
+     */
+    @ExperimentalComposeUiApi
+    val TestTagsAsResourceId = SemanticsPropertyKey<Boolean>(
+        name = "TestTagsAsResourceId",
+        mergePolicy = { parentValue, _ -> parentValue }
+    )
+}
+
+/**
+ * Configuration toggle to map testTags to resource-id.
+ *
+ * This provides a way of filling in AccessibilityNodeInfo.viewIdResourceName, which in the View System
+ * is populated based on the resource string in the XML.
+ *
+ * testTags are also provided in AccessibilityNodeInfo.extras under key
+ * "androidx.compose.ui.semantics.testTag". However, when using UIAutomator or on Android 7 and below,
+ * extras are not available, so a more backwards-compatible way of making testTags available to
+ * accessibility-tree-based integration tests is sometimes needed. resource-id was the most natural
+ * property to repurpose for this.
+ *
+ * This property applies to a semantics subtree. For example, if it's set to true on the root semantics
+ * node of the app (and no child nodes set it back to false), then every testTag will be mapped.
+ */
+@ExperimentalComposeUiApi
+var SemanticsPropertyReceiver.testTagsAsResourceId by
+    SemanticsPropertiesAndroid.TestTagsAsResourceId
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
index ffa0283..03dabc0 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
@@ -774,9 +774,16 @@
  */
 var SemanticsPropertyReceiver.role by SemanticsProperties.Role
 
-// TODO(b/138172781): Move to FoundationSemanticsProperties.kt
 /**
  * Test tag attached to this semantics node.
+ *
+ * This can be used to find nodes in testing frameworks:
+ * - In Compose's built-in unit test framework, use with
+ * [onNodeWithTag][androidx.compose.ui.test.onNodeWithTag].
+ * - For newer AccessibilityNodeInfo-based integration test frameworks, it can be matched in the
+ * extras with key "androidx.compose.ui.semantics.testTag"
+ * - For legacy AccessibilityNodeInfo-based integration tests, it's optionally exposed as the
+ * resource id if [testTagsAsResourceId] is true (for matching with 'By.res' in UIAutomator).
  */
 var SemanticsPropertyReceiver.testTag by SemanticsProperties.TestTag
 
diff --git a/hilt/hilt-compiler/build.gradle b/hilt/hilt-compiler/build.gradle
index c105976..9494a98 100644
--- a/hilt/hilt-compiler/build.gradle
+++ b/hilt/hilt-compiler/build.gradle
@@ -39,7 +39,11 @@
     testImplementation(libs.googleCompileTesting)
     testImplementation(libs.hiltCore)
     testImplementation(fileTree(
-            dir: "${new File(project(":hilt:hilt-work").buildDir, "libJar")}",
+            dir: provider {
+                // Replace with AGP API once it is added b/228109260
+                // Wrapping in a provider as a workaround as we access buildDir before this project is configured
+                "${new File(project(":hilt:hilt-work").buildDir, "libJar")}"
+            },
             include : "*.jar"))
     testImplementation(fileTree(
             dir: "${SdkHelperKt.getSdkPath(project)}/platforms/$SupportConfig.COMPILE_SDK_VERSION/",
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsSupportFragmentTest.java b/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsSupportFragmentTest.java
index 13e4550..f235494 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsSupportFragmentTest.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsSupportFragmentTest.java
@@ -430,6 +430,7 @@
         navigateBetweenRowsAndVideoUsingDPADInternal(DetailsSupportFragmentWithVideo1.class);
     }
 
+    @FlakyTest(bugId = 228336699)
     @Test
     public void navigateBetweenRowsAndVideoUsingDPAD2() throws Throwable {
         navigateBetweenRowsAndVideoUsingDPADInternal(DetailsSupportFragmentWithVideo2.class);
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/app/GuidedStepSupportFragmentTest.java b/leanback/leanback/src/androidTest/java/androidx/leanback/app/GuidedStepSupportFragmentTest.java
index db8c3a7..3d3e5c6 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/app/GuidedStepSupportFragmentTest.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/app/GuidedStepSupportFragmentTest.java
@@ -462,6 +462,7 @@
         assertEquals(1000, actionCapture1.getValue().getId());
     }
 
+    @FlakyTest(bugId = 228337304)
     @Test
     public void tapEditTitle() throws Throwable {
         final String fragmentName = generateMethodTestName("first");
diff --git a/navigation/navigation-safe-args-generator/build.gradle b/navigation/navigation-safe-args-generator/build.gradle
index 5327a64..dda3c51 100644
--- a/navigation/navigation-safe-args-generator/build.gradle
+++ b/navigation/navigation-safe-args-generator/build.gradle
@@ -38,11 +38,19 @@
             include : "android.jar"
     ))
     testImplementation(fileTree(
-            dir: "${new File(project(":navigation:navigation-common").buildDir, "libJar")}",
+            dir: provider {
+                // Wrapping in a provider as a workaround as we access buildDir before this project is configured
+                // Replace with AGP API once it is added b/228109260
+                "${new File(project(":navigation:navigation-common").buildDir, "libJar")}"
+            },
             include : "*.jar"
     ))
     testImplementation(fileTree(
-            dir: "${new File(project(":lifecycle:lifecycle-viewmodel-savedstate").buildDir, "libJar")}",
+            dir: provider {
+                // Wrapping in a provider as a workaround as we access buildDir before this project is configured
+                // Replace with AGP API once it is added b/228109260
+                "${new File(project(":lifecycle:lifecycle-viewmodel-savedstate").buildDir, "libJar")}"
+            },
             include : "*.jar"
     ))
 }
diff --git a/room/room-compiler/build.gradle b/room/room-compiler/build.gradle
index 8e4ae16..5c8afcd 100644
--- a/room/room-compiler/build.gradle
+++ b/room/room-compiler/build.gradle
@@ -114,11 +114,19 @@
             include : "android.jar"
     ))
     testImplementation(fileTree(
-            dir: "${new File(project(":room:room-runtime").buildDir, "intermediates/runtime_library_classes_jar/release/")}",
+            dir: provider {
+                // Wrapping in a provider as we access buildDir before this project is configured
+                // Replace with AGP API once it is added b/228109260
+                "${new File(project(":room:room-runtime").buildDir, "intermediates/runtime_library_classes_jar/release/")}"
+            },
             include : "*.jar"
     ))
     testImplementation(fileTree(
-            dir: "${new File(project(":sqlite:sqlite").buildDir, "libJar")}",
+            dir: provider {
+                // Wrapping in a provider as we access buildDir before this project is configured
+                // Replace with AGP API once it is added b/228109260
+                "${new File(project(":sqlite:sqlite").buildDir, "libJar")}"
+            },
             include : "*.jar"
     ))
     testImplementation(project(":internal-testutils-common"))
diff --git a/settings.gradle b/settings.gradle
index 6b38b3f..cb18ae6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,12 +33,19 @@
 ).absolutePath
 def rootProjectRepositories
 
+apply from: "buildSrc/out.gradle"
+def (outDir, buildSrcOut) = init.getOutDir()
+
 getGradle().beforeProject {
     // Migrate to dependencyResolutionManagement.repositories when
     // https://github.com/gradle/gradle/issues/17295 is fixed
     if (it.path == ":") {
         repos.addMavenRepositories(it.repositories)
         rootProjectRepositories = it.repositories
+
+        // Set buildSrcOut and outDir extras on root project
+        it.ext.buildSrcOut = buildSrcOut
+        it.ext.outDir = outDir
     } else {
         // Performance optimization because it is more efficient to reuse
         // repositories from the root project than recreate identical ones
@@ -46,6 +53,8 @@
         it.repositories.addAll(rootProjectRepositories)
     }
     it.ext.prebuiltsRoot = prebuiltsRoot
+    // Expected out directory structure for :foo:bar is out/androidx/foo/bar
+    it.buildDir = new File(outDir, "androidx/${it.path.replace(":", "/")}/build")
 }
 
 apply(plugin: "com.gradle.enterprise")