Merge "Reject value classes with non-public constructors or underlying property." into androidx-main
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt
index da4c9b8..f7709f6 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt
@@ -122,14 +122,15 @@
     private val interopExtensionSessionStateCallback: CameraExtensionSession.StateCallback? = null,
     private val threads: Threads
 ) : CameraDeviceWrapper {
+    private val closed = atomic(false)
     private val _lastStateCallback = atomic<OnSessionFinalized?>(null)
 
     override fun createCaptureSession(
         outputs: List<Surface>,
         stateCallback: CameraCaptureSessionWrapper.StateCallback
     ): Boolean {
-        val previousStateCallback = _lastStateCallback.value
-        check(_lastStateCallback.compareAndSet(previousStateCallback, stateCallback))
+        val (success, previousStateCallback) = checkAndSetStateCallback(stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createCaptureSession") {
                 // This function was deprecated in Android Q, but is required for some
@@ -162,14 +163,15 @@
 
     @RequiresApi(31)
     override fun createExtensionSession(config: ExtensionSessionConfigData): Boolean {
-        checkNotNull(config.extensionStateCallback) {
+        val stateCallback = config.extensionStateCallback
+        checkNotNull(stateCallback) {
             "extensionStateCallback must be set to create Extension session"
         }
         checkNotNull(config.extensionMode) {
             "extensionMode must be set to create Extension session"
         }
-        val stateCallback = config.extensionStateCallback
-        val previousStateCallback = _lastStateCallback.getAndSet(stateCallback)
+        val (success, previousStateCallback) = checkAndSetStateCallback(stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createExtensionSession") {
                 val sessionConfig =
@@ -217,8 +219,8 @@
         outputs: List<Surface>,
         stateCallback: CameraCaptureSessionWrapper.StateCallback
     ): Boolean {
-        val previousStateCallback = _lastStateCallback.value
-        check(_lastStateCallback.compareAndSet(previousStateCallback, stateCallback))
+        val (success, previousStateCallback) = checkAndSetStateCallback(stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createReprocessableCaptureSession") {
                 // This function was deprecated in Android Q, but is required for some
@@ -255,8 +257,8 @@
         outputs: List<Surface>,
         stateCallback: CameraCaptureSessionWrapper.StateCallback
     ): Boolean {
-        val previousStateCallback = _lastStateCallback.value
-        check(_lastStateCallback.compareAndSet(previousStateCallback, stateCallback))
+        val (success, previousStateCallback) = checkAndSetStateCallback(stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createConstrainedHighSpeedCaptureSession") {
                 // This function was deprecated in Android Q, but is required for some
@@ -293,8 +295,8 @@
         outputConfigurations: List<OutputConfigurationWrapper>,
         stateCallback: CameraCaptureSessionWrapper.StateCallback
     ): Boolean {
-        val previousStateCallback = _lastStateCallback.value
-        check(_lastStateCallback.compareAndSet(previousStateCallback, stateCallback))
+        val (success, previousStateCallback) = checkAndSetStateCallback(stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createCaptureSessionByOutputConfigurations") {
                 // This function was deprecated in Android Q, but is required for some
@@ -332,8 +334,8 @@
         outputs: List<OutputConfigurationWrapper>,
         stateCallback: CameraCaptureSessionWrapper.StateCallback
     ): Boolean {
-        val previousStateCallback = _lastStateCallback.value
-        check(_lastStateCallback.compareAndSet(previousStateCallback, stateCallback))
+        val (success, previousStateCallback) = checkAndSetStateCallback(stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createReprocessableCaptureSessionByConfigurations") {
                 // This function was deprecated in Android Q, but is required for some
@@ -371,9 +373,8 @@
 
     @RequiresApi(28)
     override fun createCaptureSession(config: SessionConfigData): Boolean {
-        val stateCallback = config.stateCallback
-        val previousStateCallback = _lastStateCallback.value
-        check(_lastStateCallback.compareAndSet(previousStateCallback, stateCallback))
+        val (success, previousStateCallback) = checkAndSetStateCallback(config.stateCallback)
+        if (!success) return false
         val result =
             instrumentAndCatch("createCaptureSession") {
                 val sessionConfig =
@@ -383,7 +384,7 @@
                         config.executor,
                         AndroidCaptureSessionStateCallback(
                             this,
-                            stateCallback,
+                            config.stateCallback,
                             previousStateCallback,
                             cameraErrorListener,
                             interopSessionStateCallback,
@@ -476,8 +477,10 @@
     }
 
     override fun onDeviceClosed() {
-        val lastStateCallback = _lastStateCallback.getAndSet(null)
-        lastStateCallback?.onSessionFinalized()
+        if (closed.compareAndSet(expect = false, update = true)) {
+            val lastStateCallback = _lastStateCallback.getAndSet(null)
+            lastStateCallback?.onSessionFinalized()
+        }
     }
 
     @Suppress("UNCHECKED_CAST")
@@ -495,6 +498,16 @@
         Debug.instrument("CXCP#$fnName-${cameraId.value}") {
             catchAndReportCameraExceptions(cameraId, cameraErrorListener, block)
         }
+
+    private fun checkAndSetStateCallback(
+        stateCallback: OnSessionFinalized
+    ): Pair<Boolean, OnSessionFinalized?> {
+        if (closed.value) {
+            stateCallback.onSessionFinalized()
+            return Pair(false, null)
+        }
+        return Pair(true, _lastStateCallback.getAndSet(stateCallback))
+    }
 }
 
 /**
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
index bb7966b..1173955 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
@@ -20,7 +20,6 @@
 
 import android.view.MotionEvent.ACTION_HOVER_ENTER
 import android.view.MotionEvent.ACTION_HOVER_EXIT
-import androidx.collection.IntObjectMap
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.Modifier
@@ -63,7 +62,6 @@
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
@@ -3419,9 +3417,6 @@
     override val focusOwner: FocusOwner
         get() = TODO("Not yet implemented")
 
-    override val semanticsOwner: SemanticsOwner
-        get() = TODO("Not yet implemented")
-
     override val windowInfo: WindowInfo
         get() = TODO("Not yet implemented")
 
@@ -3567,12 +3562,8 @@
     }
 
     override var measureIteration: Long = 0
-
     override val viewConfiguration: ViewConfiguration
         get() = TODO("Not yet implemented")
 
-    override val layoutNodes: IntObjectMap<LayoutNode>
-        get() = TODO("Not yet implemented")
-
     override val sharedDrawScope = LayoutNodeDrawScope()
 }
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
index 4c6c8245..2552b929 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
@@ -21,8 +21,6 @@
 import android.view.InputDevice
 import android.view.KeyEvent as AndroidKeyEvent
 import android.view.MotionEvent
-import androidx.collection.IntObjectMap
-import androidx.collection.intObjectMapOf
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.Modifier
@@ -59,8 +57,6 @@
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.semantics.EmptySemanticsModifier
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
@@ -2851,9 +2847,6 @@
     override val rootForTest: RootForTest
         get() = TODO("Not yet implemented")
 
-    override val layoutNodes: IntObjectMap<LayoutNode>
-        get() = TODO("Not yet implemented")
-
     override val hapticFeedBack: HapticFeedback
         get() = TODO("Not yet implemented")
 
@@ -2914,9 +2907,6 @@
     override val focusOwner: FocusOwner
         get() = TODO("Not yet implemented")
 
-    override val semanticsOwner: SemanticsOwner =
-        SemanticsOwner(root, EmptySemanticsModifier(), intObjectMapOf())
-
     override val windowInfo: WindowInfo
         get() = TODO("Not yet implemented")
 
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
index 8295452..ca6ec66 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
@@ -18,8 +18,6 @@
 
 package androidx.compose.ui.layout
 
-import androidx.collection.IntObjectMap
-import androidx.collection.intObjectMapOf
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.autofill.Autofill
@@ -54,8 +52,6 @@
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.semantics.EmptySemanticsModifier
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
@@ -165,12 +161,7 @@
 
     override fun onDetach(node: LayoutNode) {}
 
-    override val root: LayoutNode = LayoutNode()
-
-    override val semanticsOwner: SemanticsOwner =
-        SemanticsOwner(root, EmptySemanticsModifier(), intObjectMapOf())
-
-    override val layoutNodes: IntObjectMap<LayoutNode>
+    override val root: LayoutNode
         get() = TODO("Not yet implemented")
 
     override val sharedDrawScope: LayoutNodeDrawScope
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
index 56e499a..fd30536 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
@@ -18,8 +18,6 @@
 
 package androidx.compose.ui.node
 
-import androidx.collection.IntObjectMap
-import androidx.collection.intObjectMapOf
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.Modifier
@@ -50,8 +48,6 @@
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
 import androidx.compose.ui.platform.invertTo
-import androidx.compose.ui.semantics.EmptySemanticsModifier
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
@@ -389,9 +385,6 @@
     override val density: Density
         get() = Density(1f)
 
-    override val layoutNodes: IntObjectMap<LayoutNode>
-        get() = TODO("Not yet implemented")
-
     override val layoutDirection: LayoutDirection
         get() = LayoutDirection.Ltr
 
@@ -428,9 +421,6 @@
     override val focusOwner: FocusOwner
         get() = TODO("Not yet implemented")
 
-    override val semanticsOwner: SemanticsOwner =
-        SemanticsOwner(root, EmptySemanticsModifier(), intObjectMapOf())
-
     override val windowInfo: WindowInfo
         get() = TODO("Not yet implemented")
 
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsInfoTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsInfoTest.kt
deleted file mode 100644
index 79bad61..0000000
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsInfoTest.kt
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 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 androidx.compose.ui.semantics
-
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.node.RootForTest
-import androidx.compose.ui.platform.LocalView
-import androidx.compose.ui.semantics.SemanticsProperties.TestTag
-import androidx.compose.ui.test.junit4.ComposeContentTestRule
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithTag
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import com.google.common.truth.Correspondence
-import com.google.common.truth.Truth.assertThat
-import kotlin.test.Test
-import org.junit.Rule
-import org.junit.runner.RunWith
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-class SemanticsInfoTest {
-
-    @get:Rule val rule = createComposeRule()
-
-    lateinit var semanticsOwner: SemanticsOwner
-
-    @Test
-    fun contentWithNoSemantics() {
-        // Arrange.
-        rule.setTestContent { Box {} }
-        rule.waitForIdle()
-
-        // Act.
-        val rootSemantics = semanticsOwner.rootInfo
-
-        // Assert.
-        assertThat(rootSemantics).isNotNull()
-        assertThat(rootSemantics.parentInfo).isNull()
-        assertThat(rootSemantics.childrenInfo.size).isEqualTo(1)
-
-        // Assert extension Functions.
-        assertThat(rootSemantics.findSemanticsParent()).isNull()
-        assertThat(rootSemantics.findMergingSemanticsParent()).isNull()
-        assertThat(rootSemantics.findSemanticsChildren()).isEmpty()
-    }
-
-    @Test
-    fun singleSemanticsModifier() {
-        // Arrange.
-        rule.setTestContent { Box(Modifier.semantics { this.testTag = "testTag" }) }
-        rule.waitForIdle()
-
-        // Act.
-        val rootSemantics = semanticsOwner.rootInfo
-        val semantics = rule.getSemanticsInfoForTag("testTag")!!
-
-        // Assert.
-        assertThat(rootSemantics.parentInfo).isNull()
-        assertThat(rootSemantics.childrenInfo.asMutableList()).containsExactly(semantics)
-
-        assertThat(semantics.parentInfo).isEqualTo(rootSemantics)
-        assertThat(semantics.childrenInfo.size).isEqualTo(0)
-
-        // Assert extension Functions.
-        assertThat(rootSemantics.findSemanticsParent()).isNull()
-        assertThat(rootSemantics.findMergingSemanticsParent()).isNull()
-        assertThat(rootSemantics.findSemanticsChildren().map { it.semanticsConfiguration })
-            .comparingElementsUsing(SemanticsConfigurationComparator)
-            .containsExactly(SemanticsConfiguration().apply { testTag = "testTag" })
-
-        assertThat(semantics.findSemanticsParent()).isEqualTo(rootSemantics)
-        assertThat(semantics.findMergingSemanticsParent()).isNull()
-        assertThat(semantics.findSemanticsChildren()).isEmpty()
-    }
-
-    @Test
-    fun twoSemanticsModifiers() {
-        // Arrange.
-        rule.setTestContent {
-            Box(Modifier.semantics { this.testTag = "item1" })
-            Box(Modifier.semantics { this.testTag = "item2" })
-        }
-        rule.waitForIdle()
-
-        // Act.
-        val rootSemantics: SemanticsInfo = semanticsOwner.rootInfo
-        val semantics1 = rule.getSemanticsInfoForTag("item1")
-        val semantics2 = rule.getSemanticsInfoForTag("item2")
-
-        // Assert.
-        assertThat(rootSemantics.parentInfo).isNull()
-        assertThat(rootSemantics.childrenInfo.map { it.semanticsConfiguration }.toList())
-            .comparingElementsUsing(SemanticsConfigurationComparator)
-            .containsExactly(
-                SemanticsConfiguration().apply { testTag = "item1" },
-                SemanticsConfiguration().apply { testTag = "item2" }
-            )
-            .inOrder()
-
-        assertThat(rootSemantics.findSemanticsChildren().map { it.semanticsConfiguration })
-            .comparingElementsUsing(SemanticsConfigurationComparator)
-            .containsExactly(
-                SemanticsConfiguration().apply { testTag = "item1" },
-                SemanticsConfiguration().apply { testTag = "item2" }
-            )
-            .inOrder()
-
-        checkNotNull(semantics1)
-        assertThat(semantics1.parentInfo).isEqualTo(rootSemantics)
-        assertThat(semantics1.childrenInfo.size).isEqualTo(0)
-
-        checkNotNull(semantics2)
-        assertThat(semantics2.parentInfo).isEqualTo(rootSemantics)
-        assertThat(semantics2.childrenInfo.size).isEqualTo(0)
-
-        // Assert extension Functions.
-        assertThat(rootSemantics.findSemanticsParent()).isNull()
-        assertThat(rootSemantics.findMergingSemanticsParent()).isNull()
-        assertThat(rootSemantics.findSemanticsChildren().map { it.semanticsConfiguration })
-            .comparingElementsUsing(SemanticsConfigurationComparator)
-            .containsExactly(
-                SemanticsConfiguration().apply { testTag = "item1" },
-                SemanticsConfiguration().apply { testTag = "item2" }
-            )
-            .inOrder()
-
-        assertThat(semantics1.findSemanticsParent()).isEqualTo(rootSemantics)
-        assertThat(semantics1.findMergingSemanticsParent()).isNull()
-        assertThat(semantics1.findSemanticsChildren()).isEmpty()
-
-        assertThat(semantics2.findSemanticsParent()).isEqualTo(rootSemantics)
-        assertThat(semantics2.findMergingSemanticsParent()).isNull()
-        assertThat(semantics2.findSemanticsChildren()).isEmpty()
-    }
-
-    // TODO(ralu): Split this into multiple tests.
-    @Test
-    fun nodeDeepInHierarchy() {
-        // Arrange.
-        rule.setTestContent {
-            Column(Modifier.semantics(mergeDescendants = true) { testTag = "outerColumn" }) {
-                Row(Modifier.semantics { testTag = "outerRow" }) {
-                    Column(Modifier.semantics(mergeDescendants = true) { testTag = "column" }) {
-                        Row(Modifier.semantics { testTag = "row" }) {
-                            Column {
-                                Box(Modifier.semantics { testTag = "box" })
-                                Row(
-                                    Modifier.semantics {}
-                                        .semantics { testTag = "testTarget" }
-                                        .semantics { testTag = "extra modifier2" }
-                                ) {
-                                    Box { Box(Modifier.semantics { testTag = "child1" }) }
-                                    Box(Modifier.semantics { testTag = "child2" }) {
-                                        Box(Modifier.semantics { testTag = "grandChild" })
-                                    }
-                                    Box {}
-                                    Row {
-                                        Box {}
-                                        Box {}
-                                    }
-                                    Box { Box(Modifier.semantics { testTag = "child3" }) }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        rule.waitForIdle()
-        val row = rule.getSemanticsInfoForTag(tag = "row", useUnmergedTree = true)
-        val column = rule.getSemanticsInfoForTag("column")
-
-        // Act.
-        val testTarget = rule.getSemanticsInfoForTag(tag = "testTarget", useUnmergedTree = true)
-
-        // Assert.
-        checkNotNull(testTarget)
-        assertThat(testTarget.parentInfo).isNotEqualTo(row)
-        assertThat(testTarget.findSemanticsParent()).isEqualTo(row)
-        assertThat(testTarget.findMergingSemanticsParent()).isEqualTo(column)
-        assertThat(testTarget.childrenInfo.size).isEqualTo(5)
-        assertThat(testTarget.findSemanticsChildren().map { it.semanticsConfiguration })
-            .comparingElementsUsing(SemanticsConfigurationComparator)
-            .containsExactly(
-                SemanticsConfiguration().apply { testTag = "child1" },
-                SemanticsConfiguration().apply { testTag = "child2" },
-                SemanticsConfiguration().apply { testTag = "child3" }
-            )
-            .inOrder()
-        assertThat(testTarget.semanticsConfiguration?.getOrNull(TestTag)).isEqualTo("testTarget")
-    }
-
-    private fun ComposeContentTestRule.setTestContent(composable: @Composable () -> Unit) {
-        setContent {
-            semanticsOwner = (LocalView.current as RootForTest).semanticsOwner
-            composable()
-        }
-    }
-
-    /** Helper function that returns a list of children that is easier to assert on in tests. */
-    private fun SemanticsInfo.findSemanticsChildren(): List<SemanticsInfo> {
-        val children = mutableListOf<SemanticsInfo>()
-        this@findSemanticsChildren.findSemanticsChildren { children.add(it) }
-        return children
-    }
-
-    private fun ComposeContentTestRule.getSemanticsInfoForTag(
-        tag: String,
-        useUnmergedTree: Boolean = true
-    ): SemanticsInfo? {
-        return semanticsOwner[onNodeWithTag(tag, useUnmergedTree).semanticsId()]
-    }
-
-    companion object {
-        private val SemanticsConfigurationComparator =
-            Correspondence.from<SemanticsConfiguration, SemanticsConfiguration>(
-                { actual, expected ->
-                    actual != null &&
-                        expected != null &&
-                        actual.getOrNull(TestTag) == expected.getOrNull(TestTag)
-                },
-                "has same test tag as "
-            )
-    }
-}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt
deleted file mode 100644
index 77965fe..0000000
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Copyright 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 androidx.compose.ui.semantics
-
-import androidx.compose.foundation.border
-import androidx.compose.foundation.focusable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.size
-import androidx.compose.material.Text
-import androidx.compose.material.TextField
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.ComposeUiFlags
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.isExactly
-import androidx.compose.ui.focus.onFocusChanged
-import androidx.compose.ui.graphics.Color.Companion.Black
-import androidx.compose.ui.graphics.Color.Companion.Red
-import androidx.compose.ui.node.RootForTest
-import androidx.compose.ui.node.SemanticsModifierNode
-import androidx.compose.ui.node.invalidateSemantics
-import androidx.compose.ui.platform.LocalView
-import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.test.SemanticsNodeInteraction
-import androidx.compose.ui.test.junit4.ComposeContentTestRule
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithTag
-import androidx.compose.ui.test.requestFocus
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.fastJoinToString
-import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth.assertThat
-import kotlin.test.Test
-import org.junit.Before
-import org.junit.Rule
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@MediumTest
-@RunWith(Parameterized::class)
-class SemanticsListenerTest(private val isSemanticAutofillEnabled: Boolean) {
-
-    @get:Rule val rule = createComposeRule()
-
-    private lateinit var semanticsOwner: SemanticsOwner
-
-    companion object {
-        @JvmStatic
-        @Parameterized.Parameters(name = "isSemanticAutofillEnabled = {0}")
-        fun initParameters() = listOf(false, true)
-    }
-
-    @Before
-    fun setup() {
-        @OptIn(ExperimentalComposeUiApi::class)
-        ComposeUiFlags.isSemanticAutofillEnabled = isSemanticAutofillEnabled
-    }
-
-    // Initial layout does not trigger listeners. Users have to detect the initial semantics
-    //  values by detecting first layout (You can get the bounds from RectManager.RectList).
-    @Test
-    fun initialComposition_doesNotTriggerListeners() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Text(text = "text")
-        }
-
-        // Assert.
-        rule.runOnIdle { assertThat(events).isEmpty() }
-    }
-
-    @Test
-    fun addingNonSemanticsModifier() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var addModifier by mutableStateOf(false)
-        val text = AnnotatedString("text")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(
-                modifier =
-                    Modifier.then(if (addModifier) Modifier.size(1000.dp) else Modifier)
-                        .semantics { this.text = text }
-                        .testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle { addModifier = true }
-
-        // Assert.
-        rule.runOnIdle { assertThat(events).isEmpty() }
-    }
-
-    @Test
-    fun removingNonSemanticsModifier() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var removeModifier by mutableStateOf(false)
-        val text = AnnotatedString("text")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(
-                modifier =
-                    Modifier.then(if (removeModifier) Modifier else Modifier.size(1000.dp))
-                        .semantics { this.text = text }
-                        .testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle { removeModifier = true }
-
-        // Assert.
-        rule.runOnIdle { assertThat(events).isEmpty() }
-    }
-
-    @Test
-    fun addingSemanticsModifier() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var addModifier by mutableStateOf(false)
-        val text = AnnotatedString("text")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(
-                modifier =
-                    Modifier.size(100.dp)
-                        .then(
-                            if (addModifier) Modifier.semantics { this.text = text } else Modifier
-                        )
-                        .testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle { addModifier = true }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = null, newSemantics = "text"))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun removingSemanticsModifier() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var removeModifier by mutableStateOf(false)
-        val text = AnnotatedString("text")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(
-                modifier =
-                    Modifier.size(1000.dp)
-                        .then(
-                            if (removeModifier) Modifier
-                            else Modifier.semantics { this.text = text }
-                        )
-                        .testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle { removeModifier = true }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = "text", newSemantics = null))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun changingMutableSemanticsProperty() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var text by mutableStateOf(AnnotatedString("text1"))
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(modifier = Modifier.semantics { this.text = text }.testTag("item"))
-        }
-
-        // Act.
-        rule.runOnIdle { text = AnnotatedString("text2") }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = "text1", newSemantics = "text2"))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun changingMutableSemanticsProperty_alongWithRecomposition() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var text by mutableStateOf(AnnotatedString("text1"))
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(
-                modifier =
-                    Modifier.border(2.dp, if (text.text == "text1") Red else Black)
-                        .semantics { this.text = text }
-                        .testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle { text = AnnotatedString("text2") }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = "text1", newSemantics = "text2"))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun changingSemanticsProperty_andCallingInvalidateSemantics() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        val modifierNode =
-            object : SemanticsModifierNode, Modifier.Node() {
-                override fun SemanticsPropertyReceiver.applySemantics() {}
-            }
-        var text = AnnotatedString("text1")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Box(
-                modifier =
-                    Modifier.elementFor(modifierNode).semantics { this.text = text }.testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle {
-            text = AnnotatedString("text2")
-            modifierNode.invalidateSemantics()
-        }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = "text1", newSemantics = "text2"))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun textChange() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var text by mutableStateOf("text1")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Text(text = text, modifier = Modifier.testTag("item"))
-        }
-
-        // Act.
-        rule.runOnIdle { text = "text2" }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = "text1", newSemantics = "text2"))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun multipleTextChanges() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var text by mutableStateOf("text1")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(Event(info.semanticsId, prev?.Text, info.semanticsConfiguration?.Text))
-            }
-        ) {
-            Text(text = text, modifier = Modifier.testTag("item"))
-        }
-
-        // Act.
-        rule.runOnIdle { text = "text2" }
-        rule.runOnIdle { text = "text3" }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(
-                        Event(semanticsId, prevSemantics = "text1", newSemantics = "text2"),
-                        Event(semanticsId, prevSemantics = "text2", newSemantics = "text3")
-                    )
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun EditTextChange() {
-        // Arrange.
-        val events = mutableListOf<Event<String>>()
-        var text by mutableStateOf("text1")
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(
-                    Event(
-                        info.semanticsId,
-                        prev?.EditableText,
-                        info.semanticsConfiguration?.EditableText
-                    )
-                )
-            }
-        ) {
-            TextField(
-                value = text,
-                onValueChange = { text = it },
-                modifier = Modifier.testTag("item")
-            )
-        }
-
-        // Act.
-        rule.runOnIdle { text = "text2" }
-
-        // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(Event(semanticsId, prevSemantics = "text1", newSemantics = "text2"))
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun FocusChange_withNoRecomposition() {
-        // Arrange.
-        val events = mutableListOf<Event<Boolean>>()
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(
-                    Event(
-                        info.semanticsId,
-                        prev?.getOrNull(SemanticsProperties.Focused),
-                        info.semanticsConfiguration?.getOrNull(SemanticsProperties.Focused)
-                    )
-                )
-            }
-        ) {
-            Column {
-                Box(Modifier.testTag("item1").size(100.dp).focusable())
-                Box(Modifier.testTag("item2").size(100.dp).focusable())
-            }
-        }
-        rule.onNodeWithTag("item1").requestFocus()
-        rule.runOnIdle { events.clear() }
-
-        // Act.
-        rule.onNodeWithTag("item2").requestFocus()
-
-        // Assert.
-        val item1 = rule.onNodeWithTag("item1").semanticsId
-        val item2 = rule.onNodeWithTag("item2").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(
-                        Event(item1, prevSemantics = true, newSemantics = false),
-                        Event(item2, prevSemantics = false, newSemantics = true)
-                    )
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    @Test
-    fun FocusChange_thatCausesRecomposition() {
-        // Arrange.
-        val events = mutableListOf<Event<Boolean>>()
-        rule.setTestContent(
-            onSemanticsChange = { info, prev ->
-                events.add(
-                    Event(
-                        info.semanticsId,
-                        prev?.getOrNull(SemanticsProperties.Focused),
-                        info.semanticsConfiguration?.getOrNull(SemanticsProperties.Focused)
-                    )
-                )
-            }
-        ) {
-            Column {
-                FocusableBox(Modifier.testTag("item1"))
-                FocusableBox(Modifier.testTag("item2"))
-            }
-        }
-        rule.onNodeWithTag("item1").requestFocus()
-        rule.runOnIdle { events.clear() }
-
-        // Act.
-        rule.onNodeWithTag("item2").requestFocus()
-
-        // Assert.
-        val item1 = rule.onNodeWithTag("item1").semanticsId
-        val item2 = rule.onNodeWithTag("item2").semanticsId
-        rule.runOnIdle {
-            if (isSemanticAutofillEnabled) {
-                assertThat(events)
-                    .isExactly(
-                        Event(item1, prevSemantics = true, newSemantics = false),
-                        Event(item2, prevSemantics = false, newSemantics = true)
-                    )
-            } else {
-                assertThat(events).isEmpty()
-            }
-        }
-    }
-
-    private val SemanticsConfiguration.Text
-        get() = getOrNull(SemanticsProperties.Text)?.fastJoinToString()
-
-    private val SemanticsConfiguration.EditableText
-        get() = getOrNull(SemanticsProperties.EditableText)?.toString()
-
-    private fun ComposeContentTestRule.setTestContent(
-        onSemanticsChange: (SemanticsInfo, SemanticsConfiguration?) -> Unit,
-        composable: @Composable () -> Unit
-    ) {
-        val semanticsListener =
-            object : SemanticsListener {
-                override fun onSemanticsChanged(
-                    semanticsInfo: SemanticsInfo,
-                    previousSemanticsConfiguration: SemanticsConfiguration?
-                ) {
-                    onSemanticsChange(semanticsInfo, previousSemanticsConfiguration)
-                }
-            }
-        setContent {
-            semanticsOwner = (LocalView.current as RootForTest).semanticsOwner
-            DisposableEffect(semanticsOwner) {
-                semanticsOwner.listeners.add(semanticsListener)
-                onDispose { semanticsOwner.listeners.remove(semanticsListener) }
-            }
-            composable()
-        }
-    }
-
-    data class Event<T>(val semanticsId: Int, val prevSemantics: T?, val newSemantics: T?)
-
-    // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-    private val SemanticsNodeInteraction.semanticsId: Int
-        get() = fetchSemanticsNode().id
-
-    @Composable
-    private fun FocusableBox(
-        modifier: Modifier = Modifier,
-        content: @Composable BoxScope.() -> Unit = {}
-    ) {
-        var borderColor by remember { mutableStateOf(Black) }
-        Box(
-            modifier =
-                modifier
-                    .size(100.dp)
-                    .onFocusChanged { borderColor = if (it.isFocused) Red else Black }
-                    .border(2.dp, borderColor)
-                    .focusable(),
-            content = content
-        )
-    }
-}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillManager.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillManager.android.kt
index b86440d..ff82cbf 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillManager.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillManager.android.kt
@@ -298,8 +298,6 @@
                     SemanticsContentDataType
                 )
         }
-    // TODO(b/138549623): Instead of creating a flattened tree by using the nodes from the map, we
-    //  can use SemanticsOwner to get the root SemanticsInfo and create a more representative tree.
     var index = AutofillApi26Helper.addChildCount(root, count)
 
     // Iterate through currentSemanticsNodes, finding autofill-related nodes
@@ -479,7 +477,7 @@
 }
 
 @RequiresApi(Build.VERSION_CODES.O)
-private class AutofillManagerWrapperImpl(val view: View) : AutofillManagerWrapper {
+private class AutofillManagerWrapperImpl(val view: AndroidComposeView) : AutofillManagerWrapper {
     override val autofillManager =
         view.context.getSystemService(PlatformAndroidManager::class.java)
             ?: error("Autofill service could not be located.")
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index 7dc9d64..dfac967 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -63,8 +63,6 @@
 import androidx.annotation.DoNotInline
 import androidx.annotation.RequiresApi
 import androidx.annotation.VisibleForTesting
-import androidx.collection.MutableIntObjectMap
-import androidx.collection.mutableIntObjectMapOf
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
@@ -431,12 +429,9 @@
                     .then(dragAndDropManager.modifier)
         }
 
-    override val layoutNodes: MutableIntObjectMap<LayoutNode> = mutableIntObjectMapOf()
-
     override val rootForTest: RootForTest = this
 
-    override val semanticsOwner: SemanticsOwner =
-        SemanticsOwner(root, rootSemanticsNode, layoutNodes)
+    override val semanticsOwner: SemanticsOwner = SemanticsOwner(root, rootSemanticsNode)
     private val composeAccessibilityDelegate = AndroidComposeViewAccessibilityDelegateCompat(this)
     internal var contentCaptureManager =
         AndroidContentCaptureManager(
@@ -1031,12 +1026,9 @@
         composeAccessibilityDelegate.SendRecurringAccessibilityEventsIntervalMillis = intervalMillis
     }
 
-    override fun onAttach(node: LayoutNode) {
-        layoutNodes[node.semanticsId] = node
-    }
+    override fun onAttach(node: LayoutNode) {}
 
     override fun onDetach(node: LayoutNode) {
-        layoutNodes.remove(node.semanticsId)
         measureAndLayoutDelegate.onNodeDetached(node)
         requestClearInvalidObservations()
         @OptIn(ExperimentalComposeUiApi::class)
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 7deeca8..7036817 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
@@ -2355,11 +2355,11 @@
             if (layoutNode.nodes.has(Nodes.Semantics)) layoutNode
             else layoutNode.findClosestParentNode { it.nodes.has(Nodes.Semantics) }
 
-        val config = semanticsNode?.semanticsConfiguration ?: return
+        val config = semanticsNode?.collapsedSemantics ?: return
         if (!config.isMergingSemanticsOfDescendants) {
             semanticsNode
                 .findClosestParentNode {
-                    it.semanticsConfiguration?.isMergingSemanticsOfDescendants == true
+                    it.collapsedSemantics?.isMergingSemanticsOfDescendants == true
                 }
                 ?.let { semanticsNode = it }
         }
@@ -3264,12 +3264,12 @@
     val ancestor =
         layoutNode.findClosestParentNode {
             // looking for text field merging node
-            val ancestorSemanticsConfiguration = it.semanticsConfiguration
+            val ancestorSemanticsConfiguration = it.collapsedSemantics
             ancestorSemanticsConfiguration?.isMergingSemanticsOfDescendants == true &&
                 ancestorSemanticsConfiguration.contains(SemanticsProperties.EditableText)
         }
     return ancestor != null &&
-        ancestor.semanticsConfiguration?.getOrNull(SemanticsProperties.Focused) != true
+        ancestor.collapsedSemantics?.getOrNull(SemanticsProperties.Focused) != true
 }
 
 private fun AccessibilityAction<*>.accessibilityEquals(other: Any?): Boolean {
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index c884b74..1f96189 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -17,8 +17,6 @@
 
 package androidx.compose.ui.node
 
-import androidx.collection.IntObjectMap
-import androidx.collection.intObjectMapOf
 import androidx.compose.testutils.TestViewConfiguration
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
@@ -68,10 +66,8 @@
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
 import androidx.compose.ui.platform.invertTo
-import androidx.compose.ui.semantics.EmptySemanticsModifier
 import androidx.compose.ui.semantics.SemanticsConfiguration
 import androidx.compose.ui.semantics.SemanticsModifier
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.semantics.SemanticsPropertyReceiver
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
@@ -2318,8 +2314,6 @@
 internal class MockOwner(
     private val position: IntOffset = IntOffset.Zero,
     override val root: LayoutNode = LayoutNode(),
-    override val semanticsOwner: SemanticsOwner =
-        SemanticsOwner(root, EmptySemanticsModifier(), intObjectMapOf()),
     override val coroutineContext: CoroutineContext =
         Executors.newFixedThreadPool(3).asCoroutineDispatcher()
 ) : Owner {
@@ -2553,9 +2547,6 @@
     override val viewConfiguration: ViewConfiguration
         get() = TODO("Not yet implemented")
 
-    override val layoutNodes: IntObjectMap<LayoutNode>
-        get() = TODO("Not yet implemented")
-
     override val sharedDrawScope = LayoutNodeDrawScope()
 }
 
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
index bc17a55..8c77a83 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
@@ -18,8 +18,6 @@
 
 package androidx.compose.ui.node
 
-import androidx.collection.IntObjectMap
-import androidx.collection.intObjectMapOf
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -52,8 +50,6 @@
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.semantics.EmptySemanticsModifier
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
@@ -337,9 +333,7 @@
 
         override fun onDetach(node: LayoutNode) {}
 
-        override val root: LayoutNode = LayoutNode()
-
-        override val layoutNodes: IntObjectMap<LayoutNode>
+        override val root: LayoutNode
             get() = TODO("Not yet implemented")
 
         override val sharedDrawScope: LayoutNodeDrawScope
@@ -381,9 +375,6 @@
         override val focusOwner: FocusOwner
             get() = TODO("Not yet implemented")
 
-        override val semanticsOwner: SemanticsOwner =
-            SemanticsOwner(root, EmptySemanticsModifier(), intObjectMapOf())
-
         override val windowInfo: WindowInfo
             get() = TODO("Not yet implemented")
 
@@ -451,7 +442,7 @@
         override fun forceMeasureTheSubtree(layoutNode: LayoutNode, affectsLookahead: Boolean) =
             TODO("Not yet implemented")
 
-        override fun onSemanticsChange() {}
+        override fun onSemanticsChange() = TODO("Not yet implemented")
 
         override fun onLayoutChange(layoutNode: LayoutNode) = TODO("Not yet implemented")
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index ace8eed..2da7de0 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -19,8 +19,6 @@
 import androidx.compose.runtime.CompositionLocalMap
 import androidx.compose.runtime.collection.MutableVector
 import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.ui.ComposeUiFlags
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
@@ -56,7 +54,6 @@
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.simpleIdentityToString
 import androidx.compose.ui.semantics.SemanticsConfiguration
-import androidx.compose.ui.semantics.SemanticsInfo
 import androidx.compose.ui.semantics.generateSemanticsId
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
@@ -91,7 +88,6 @@
     Remeasurement,
     OwnerScope,
     LayoutInfo,
-    SemanticsInfo,
     ComposeUiNode,
     InteroperableComposeUiNode,
     Owner.OnLayoutCompletedListener {
@@ -398,62 +394,43 @@
         invalidateMeasurements()
     }
 
-    private var _semanticsConfiguration: SemanticsConfiguration? = null
-    override val semanticsConfiguration: SemanticsConfiguration?
-        get() {
-            // This is needed until we completely move to the new world where we always pre-compute
-            // the semantics configuration. At that point, this can be replaced by
-            // check(!isSemanticsInvalidated) or remove this custom getter.
-            if (isSemanticsInvalidated) {
-                _semanticsConfiguration = calculateSemanticsConfiguration()
-            }
-            return _semanticsConfiguration
-        }
-
-    private fun calculateSemanticsConfiguration(): SemanticsConfiguration? {
-        if (!nodes.has(Nodes.Semantics)) return null
-
-        var config = SemanticsConfiguration()
-        requireOwner().snapshotObserver.observeSemanticsReads(this) {
-            nodes.tailToHead(Nodes.Semantics) {
-                if (it.shouldClearDescendantSemantics) {
-                    config = SemanticsConfiguration()
-                    config.isClearingSemantics = true
-                }
-                if (it.shouldMergeDescendantSemantics) {
-                    config.isMergingSemanticsOfDescendants = true
-                }
-                with(config) { with(it) { applySemantics() } }
-            }
-        }
-        return config
-    }
-
-    private var isSemanticsInvalidated = false
+    private var _collapsedSemantics: SemanticsConfiguration? = null
 
     internal fun invalidateSemantics() {
-        if (
-            @OptIn(ExperimentalComposeUiApi::class) !ComposeUiFlags.isSemanticAutofillEnabled ||
-                nodes.isUpdating ||
-                applyingModifierOnAttach
-        ) {
-            // We are currently updating the modifier, so just schedule an invalidation. After
-            // applying the modifier, we will notify listeners of semantics changes.
-            isSemanticsInvalidated = true
-        } else {
-            // We are not currently updating the modifier, so instead of scheduling invalidation,
-            // we update the semantics configuration and send the notification event right away.
-            val prev = _semanticsConfiguration
-            _semanticsConfiguration = calculateSemanticsConfiguration()
-            requireOwner().semanticsOwner.notifySemanticsChange(this, prev)
-        }
-
+        _collapsedSemantics = null
         // TODO(lmr): this ends up scheduling work that diffs the entire tree, but we should
         //  eventually move to marking just this node as invalidated since we are invalidating
         //  on a per-node level. This should preserve current behavior for now.
         requireOwner().onSemanticsChange()
     }
 
+    internal val collapsedSemantics: SemanticsConfiguration?
+        get() {
+            // TODO: investigate if there's a better way to approach "half attached" state and
+            // whether or not deactivated nodes should be considered removed or not.
+            if (!isAttached || isDeactivated) return null
+
+            if (!nodes.has(Nodes.Semantics) || _collapsedSemantics != null) {
+                return _collapsedSemantics
+            }
+
+            var config = SemanticsConfiguration()
+            requireOwner().snapshotObserver.observeSemanticsReads(this) {
+                nodes.tailToHead(Nodes.Semantics) {
+                    if (it.shouldClearDescendantSemantics) {
+                        config = SemanticsConfiguration()
+                        config.isClearingSemantics = true
+                    }
+                    if (it.shouldMergeDescendantSemantics) {
+                        config.isMergingSemanticsOfDescendants = true
+                    }
+                    with(config) { with(it) { applySemantics() } }
+                }
+            }
+            _collapsedSemantics = config
+            return config
+        }
+
     /**
      * Set the [Owner] of this LayoutNode. This LayoutNode must not already be attached. [owner]
      * must match its [parent].[owner].
@@ -486,7 +463,9 @@
         pendingModifier?.let { applyModifier(it) }
         pendingModifier = null
 
-        if (nodes.has(Nodes.Semantics)) invalidateSemantics()
+        if (nodes.has(Nodes.Semantics)) {
+            invalidateSemantics()
+        }
         owner.onAttach(this)
 
         // Update lookahead root when attached. For nested cases, we'll always use the
@@ -538,9 +517,9 @@
         }
         layoutDelegate.resetAlignmentLines()
         onDetach?.invoke(owner)
+
         if (nodes.has(Nodes.Semantics)) {
-            _semanticsConfiguration = null
-            requireOwner().onSemanticsChange()
+            invalidateSemantics()
         }
         nodes.runDetachLifecycle()
         ignoreRemeasureRequests { _foldedChildren.forEach { child -> child.detach() } }
@@ -576,10 +555,6 @@
             return _zSortedChildren
         }
 
-    @Suppress("UNCHECKED_CAST")
-    override val childrenInfo: MutableVector<SemanticsInfo>
-        get() = zSortedChildren as MutableVector<SemanticsInfo>
-
     override val isValidOwnerScope: Boolean
         get() = isAttached
 
@@ -891,14 +866,6 @@
         if (lookaheadRoot == null && nodes.has(Nodes.ApproachMeasure)) {
             lookaheadRoot = this
         }
-        // Notify semantics listeners if semantics was invalidated.
-        @OptIn(ExperimentalComposeUiApi::class)
-        if (ComposeUiFlags.isSemanticAutofillEnabled && isSemanticsInvalidated) {
-            val prev = _semanticsConfiguration
-            _semanticsConfiguration = calculateSemanticsConfiguration()
-            isSemanticsInvalidated = false
-            requireOwner().semanticsOwner.notifySemanticsChange(this, prev)
-        }
     }
 
     private fun resetModifierState() {
@@ -1303,7 +1270,7 @@
         }
     }
 
-    override val parentInfo: SemanticsInfo?
+    override val parentInfo: LayoutInfo?
         get() = parent
 
     override var isDeactivated = false
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
index c08a929..ff19036 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
@@ -40,8 +40,8 @@
     internal var head: Modifier.Node = tail
         private set
 
-    internal val isUpdating: Boolean
-        get() = head.parent != null
+    private val isUpdating: Boolean
+        get() = head === SentinelHead
 
     private val aggregateChildKindSet: Int
         get() = head.aggregateChildKindSet
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
index f102b02..0ce80dd 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
@@ -1512,7 +1512,7 @@
                 override fun interceptOutOfBoundsChildEvents(node: Modifier.Node) = false
 
                 override fun shouldHitTestChildren(parentLayoutNode: LayoutNode) =
-                    parentLayoutNode.semanticsConfiguration?.isClearingSemantics != true
+                    parentLayoutNode.collapsedSemantics?.isClearingSemantics != true
 
                 override fun childHitTest(
                     layoutNode: LayoutNode,
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index 655a320..ed5b7c2 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -18,7 +18,6 @@
 package androidx.compose.ui.node
 
 import androidx.annotation.RestrictTo
-import androidx.collection.IntObjectMap
 import androidx.compose.runtime.Applier
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
@@ -48,7 +47,6 @@
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.platform.ViewConfiguration
 import androidx.compose.ui.platform.WindowInfo
-import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
@@ -70,9 +68,6 @@
     /** The root layout node in the component tree. */
     val root: LayoutNode
 
-    /** A mapping of semantic id to LayoutNode. */
-    val layoutNodes: IntObjectMap<LayoutNode>
-
     /** Draw scope reused for drawing speed up. */
     val sharedDrawScope: LayoutNodeDrawScope
 
@@ -134,8 +129,6 @@
 
     val pointerIconService: PointerIconService
 
-    val semanticsOwner: SemanticsOwner
-
     /** Provide a focus owner that controls focus within Compose. */
     val focusOwner: FocusOwner
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/SemanticsModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/SemanticsModifierNode.kt
index 002be43..dd3e2f8 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/SemanticsModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/SemanticsModifierNode.kt
@@ -87,14 +87,7 @@
     fun SemanticsPropertyReceiver.applySemantics()
 }
 
-/**
- * Invalidate semantics associated with this node. This will reset the [SemanticsConfiguration]
- * associated with the layout node backing this modifier node, and will re-calculate it the next
- * time the [SemanticsConfiguration] is read.
- */
-fun SemanticsModifierNode.invalidateSemantics() {
-    requireLayoutNode().invalidateSemantics()
-}
+fun SemanticsModifierNode.invalidateSemantics() = requireLayoutNode().invalidateSemantics()
 
 internal val SemanticsConfiguration.useMinimumTouchTarget: Boolean
     get() = getOrNull(SemanticsActions.OnClick) != null
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsInfo.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsInfo.kt
deleted file mode 100644
index 1f2cc5d..0000000
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsInfo.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 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 androidx.compose.ui.semantics
-
-import androidx.compose.runtime.collection.MutableVector
-import androidx.compose.ui.layout.LayoutInfo
-import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.node.LayoutNode
-
-/**
- * This is an internal interface that can be used by [SemanticsListener]s to read semantic
- * information from layout nodes. The root [SemanticsInfo] can be accessed using
- * [SemanticsOwner.rootInfo], and particular [SemanticsInfo] can be looked up by their [semanticsId]
- * by using [SemanticsOwner.get].
- */
-internal interface SemanticsInfo : LayoutInfo {
-    /** The semantics configuration (Semantic properties and actions) associated with this node. */
-    val semanticsConfiguration: SemanticsConfiguration?
-
-    /**
-     * The [SemanticsInfo] of the parent.
-     *
-     * This includes parents that do not have any semantics modifiers.
-     */
-    override val parentInfo: SemanticsInfo?
-
-    /**
-     * Returns the children list sorted by their [LayoutNode.zIndex] first (smaller first) and the
-     * order they were placed via [Placeable.placeAt] by parent (smaller first). Please note that
-     * this list contains not placed items as well, so you have to manually filter them.
-     *
-     * Note that the object is reused so you shouldn't save it for later.
-     */
-    val childrenInfo: MutableVector<SemanticsInfo>
-}
-
-/** The semantics parent (nearest ancestor which has semantic properties). */
-internal fun SemanticsInfo.findSemanticsParent(): SemanticsInfo? {
-    var parent = parentInfo
-    while (parent != null) {
-        if (parent.semanticsConfiguration != null) return parent
-        parent = parent.parentInfo
-    }
-    return null
-}
-
-/** The nearest semantics ancestor that is merging descendants. */
-internal fun SemanticsInfo.findMergingSemanticsParent(): SemanticsInfo? {
-    var parent = parentInfo
-    while (parent != null) {
-        if (parent.semanticsConfiguration?.isMergingSemanticsOfDescendants == true) return parent
-        parent = parent.parentInfo
-    }
-    return null
-}
-
-internal inline fun SemanticsInfo.findSemanticsChildren(
-    includeDeactivated: Boolean = false,
-    block: (SemanticsInfo) -> Unit
-) {
-    val unvisitedStack = MutableVector<SemanticsInfo>(childrenInfo.size)
-    childrenInfo.forEachReversed { unvisitedStack += it }
-    while (unvisitedStack.isNotEmpty()) {
-        val child = unvisitedStack.removeAt(unvisitedStack.lastIndex)
-        when {
-            child.isDeactivated && !includeDeactivated -> continue
-            child.semanticsConfiguration != null -> block(child)
-            else -> child.childrenInfo.forEachReversed { unvisitedStack += it }
-        }
-    }
-}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsListener.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsListener.kt
deleted file mode 100644
index b51d7c8..0000000
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsListener.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 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 androidx.compose.ui.semantics
-
-/** A listener that can be used to observe semantic changes. */
-internal interface SemanticsListener {
-
-    /**
-     * [onSemanticsChanged] is called when the [SemanticsConfiguration] of a LayoutNode changes, or
-     * when a node calls SemanticsModifierNode.invalidateSemantics.
-     *
-     * @param semanticsInfo the current [SemanticsInfo] of the layout node that has changed.
-     * @param previousSemanticsConfiguration the previous [SemanticsConfiguration] associated with
-     *   the layout node.
-     */
-    fun onSemanticsChanged(
-        semanticsInfo: SemanticsInfo,
-        previousSemanticsConfiguration: SemanticsConfiguration?
-    )
-}
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 4bbacd0..35478d6 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
@@ -45,7 +45,7 @@
         layoutNode.nodes.head(Nodes.Semantics)!!.node,
         mergingEnabled,
         layoutNode,
-        layoutNode.semanticsConfiguration!!
+        layoutNode.collapsedSemantics!!
     )
 
 internal fun SemanticsNode(
@@ -70,7 +70,7 @@
         outerSemanticsNode.node,
         mergingEnabled,
         layoutNode,
-        layoutNode.semanticsConfiguration ?: SemanticsConfiguration()
+        layoutNode.collapsedSemantics ?: SemanticsConfiguration()
     )
 
 /**
@@ -99,7 +99,7 @@
             !isFake &&
                 replacedChildren.isEmpty() &&
                 layoutNode.findClosestParentNode {
-                    it.semanticsConfiguration?.isMergingSemanticsOfDescendants == true
+                    it.collapsedSemantics?.isMergingSemanticsOfDescendants == true
                 } == null
 
     /** The [LayoutInfo] that this is associated with. */
@@ -345,7 +345,7 @@
             if (mergingEnabled) {
                 node =
                     this.layoutNode.findClosestParentNode {
-                        it.semanticsConfiguration?.isMergingSemanticsOfDescendants == true
+                        it.collapsedSemantics?.isMergingSemanticsOfDescendants == true
                     }
             }
 
@@ -474,9 +474,7 @@
  * Executes [selector] on every parent of this [LayoutNode] and returns the closest [LayoutNode] to
  * return `true` from [selector] or null if [selector] returns false for all ancestors.
  */
-internal inline fun LayoutNode.findClosestParentNode(
-    selector: (LayoutNode) -> Boolean
-): LayoutNode? {
+internal fun LayoutNode.findClosestParentNode(selector: (LayoutNode) -> Boolean): LayoutNode? {
     var currentParent = this.parent
     while (currentParent != null) {
         if (selector(currentParent)) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
index b987155..dffed0f 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
@@ -16,8 +16,6 @@
 
 package androidx.compose.ui.semantics
 
-import androidx.collection.IntObjectMap
-import androidx.collection.MutableObjectList
 import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.util.fastForEach
 
@@ -25,8 +23,7 @@
 class SemanticsOwner
 internal constructor(
     private val rootNode: LayoutNode,
-    private val outerSemanticsNode: EmptySemanticsModifier,
-    private val nodes: IntObjectMap<LayoutNode>
+    private val outerSemanticsNode: EmptySemanticsModifier
 ) {
     /**
      * The root node of the semantics tree. Does not contain any unmerged data. May contain merged
@@ -50,22 +47,6 @@
                 unmergedConfig = SemanticsConfiguration()
             )
         }
-
-    internal val listeners = MutableObjectList<SemanticsListener>(2)
-
-    internal val rootInfo: SemanticsInfo
-        get() = rootNode
-
-    internal operator fun get(semanticsId: Int): SemanticsInfo? {
-        return nodes[semanticsId]
-    }
-
-    internal fun notifySemanticsChange(
-        semanticsInfo: SemanticsInfo,
-        previousSemanticsConfiguration: SemanticsConfiguration?
-    ) {
-        listeners.forEach { it.onSemanticsChanged(semanticsInfo, previousSemanticsConfiguration) }
-    }
 }
 
 /**
@@ -89,7 +70,6 @@
         .toList()
 }
 
-@Suppress("unused")
 @Deprecated(message = "Use a new overload instead", level = DeprecationLevel.HIDDEN)
 fun SemanticsOwner.getAllSemanticsNodes(mergingEnabled: Boolean) =
     getAllSemanticsNodes(mergingEnabled, true)