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)