Merge "Remove deprecated APIs" into androidx-main
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 d4fa383..2a94fc1 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
@@ -113,6 +113,8 @@
         private const val DisabledToggleableTag = "disabledToggleable"
         private const val TextFieldTag = "textField"
         private const val TextNodeTag = "textNode"
+        private const val OverlappedChildOneTag = "OverlappedChildOne"
+        private const val OverlappedChildTwoTag = "OverlappedChildTwo"
         private const val InputText = "hello"
         private const val InitialText = "h"
     }
@@ -159,6 +161,10 @@
                             BasicText("ToggleableText")
                         }
                     )
+                    Box {
+                        BasicText("Child One", Modifier.zIndex(1f).testTag(OverlappedChildOneTag))
+                        BasicText("Child Two", Modifier.testTag(OverlappedChildTwoTag))
+                    }
                     if (isTextFieldVisible) {
                         BasicTextField(
                             modifier = Modifier
@@ -583,6 +589,40 @@
         }
     }
 
+    @Test
+    fun testGetVirtualViewAt() {
+        var rootNodeBoundsLeft = 0f
+        var rootNodeBoundsTop = 0f
+        rule.runOnIdle {
+            val rootNode = androidComposeView.semanticsOwner.rootSemanticsNode
+            rootNodeBoundsLeft = rootNode.globalBounds.left
+            rootNodeBoundsTop = rootNode.globalBounds.top
+        }
+        val toggleableNode = rule.onNodeWithTag(ToggleableTag)
+            .fetchSemanticsNode("couldn't find node with tag $ToggleableTag")
+        val toggleableNodeBounds = toggleableNode.globalBounds
+
+        val toggleableNodeId = delegate.getVirtualViewAt(
+            (toggleableNodeBounds.left + toggleableNodeBounds.right) / 2 - rootNodeBoundsLeft,
+            (toggleableNodeBounds.top + toggleableNodeBounds.bottom) / 2 - rootNodeBoundsTop
+        )
+        assertEquals(toggleableNode.id, toggleableNodeId)
+
+        val overlappedChildOneNode = rule.onNodeWithTag(OverlappedChildOneTag)
+            .fetchSemanticsNode("couldn't find node with tag $OverlappedChildOneTag")
+        val overlappedChildTwoNode = rule.onNodeWithTag(OverlappedChildTwoTag)
+            .fetchSemanticsNode("couldn't find node with tag $OverlappedChildTwoTag")
+        val overlappedChildNodeBounds = overlappedChildTwoNode.globalBounds
+        val overlappedChildNodeId = delegate.getVirtualViewAt(
+            (overlappedChildNodeBounds.left + overlappedChildNodeBounds.right) / 2 -
+                rootNodeBoundsLeft,
+            (overlappedChildNodeBounds.top + overlappedChildNodeBounds.bottom) / 2 -
+                rootNodeBoundsTop
+        )
+        assertEquals(overlappedChildOneNode.id, overlappedChildNodeId)
+        assertNotEquals(overlappedChildTwoNode.id, overlappedChildNodeId)
+    }
+
     private fun eventIndex(list: List<AccessibilityEvent>, event: AccessibilityEvent): Int {
         for (i in list.indices) {
             if (ReflectionEquals(list[i], null).matches(event)) {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
index 97c6889..c1ed971 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
@@ -38,6 +38,7 @@
 import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.zIndex
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
@@ -426,6 +427,33 @@
             )
         }
     }
+
+    @Test
+    fun testChildrenAreZSorted() {
+        val child1 = "child1"
+        val child2 = "child2"
+        rule.setContent {
+            SimpleTestLayout(
+                Modifier.testTag(TestTag).semantics {}
+            ) {
+                SimpleTestLayout(
+                    Modifier.zIndex(1f).semantics { contentDescription = child1 }
+                ) {}
+                SimpleTestLayout(Modifier.semantics { contentDescription = child2 }) { }
+            }
+        }
+
+        val root = rule.onNodeWithTag(TestTag).fetchSemanticsNode("can't find node $TestTag")
+        assertEquals(2, root.children.size)
+        assertEquals(
+            child2,
+            root.children[0].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+        assertEquals(
+            child1,
+            root.children[1].config.getOrNull(SemanticsProperties.ContentDescription)
+        )
+    }
 }
 
 private fun SemanticsNodeInteraction.assertDoesNotHaveProperty(property: SemanticsPropertyKey<*>) {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
index 50ec9a3..f42362f 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
@@ -1114,7 +1114,8 @@
         }
     }
 
-    private fun getVirtualViewAt(x: Float, y: Float): Int {
+    @VisibleForTesting
+    internal fun getVirtualViewAt(x: Float, y: Float): Int {
         val node = view.semanticsOwner.rootSemanticsNode
         val id = findVirtualViewAt(
             x + node.globalBounds.left,
@@ -1128,8 +1129,9 @@
 
     // TODO(b/151729467): compose accessibility getVirtualViewAt needs to be more efficient
     private fun findVirtualViewAt(x: Float, y: Float, node: SemanticsNode): Int {
-        node.children.fastForEach {
-            val id = findVirtualViewAt(x, y, it)
+        val children = node.children
+        for (i in children.size - 1 downTo 0) {
+            val id = findVirtualViewAt(x, y, children[i])
             if (id != InvalidId) {
                 return id
             }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
index bca6c84..a59fd7d 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
@@ -318,7 +318,7 @@
 private fun LayoutNode.findOneLayerOfSemanticsWrappers(
     list: MutableList<SemanticsWrapper> = mutableListOf<SemanticsWrapper>()
 ): List<SemanticsWrapper> {
-    children.fastForEach { child ->
+    zSortedChildren.forEach { child ->
         val outerSemantics = child.outerSemantics
         if (outerSemantics != null) {
             list.add(outerSemantics)