diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-04-24 17:50:04 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-04-24 17:50:04 +0000 |
commit | 1e9993d8adf910412256d7a25c8b5f7fc6010085 (patch) | |
tree | 0e66e67f60b2b6c7b9582fd1f29a1d72b8cc8d3c | |
parent | d6e61cfa5ca9eeff9e09d56106c7e6d50f1021dd (diff) | |
parent | ecddfecd4194a37512a5081466b888af7b3c1a71 (diff) | |
download | support-sparse-9949164-L22700000960137459.tar.gz |
Merge "Merge cherrypicks of ['android-review.googlesource.com/2520700', 'android-review.googlesource.com/2557491', 'android-review.googlesource.com/2558170', 'android-review.googlesource.com/2544354', 'android-review.googlesource.com/2555513'] into sparse-9949164-L22700000960137459. SPARSE_CHANGE: Ia77fccb794b016d699a4b6ffef8e4fe690fc4766 SPARSE_CHANGE: I7715190081686b2b01010b35375633cfc1c6ca3b SPARSE_CHANGE: I2436c2a6b585e0063ad87d4852404f7fcc0cb8f0 SPARSE_CHANGE: I4dc771beb990020ea91d6fbf83de71145a4b6382 SPARSE_CHANGE: I28392927e6d2263ca0019b40b898d06797096041" into sparse-9949164-L22700000960137459sparse-9949164-L22700000960137459
12 files changed, 716 insertions, 18 deletions
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt index 202e7f463d4..12537a7ee43 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt @@ -111,6 +111,7 @@ class VersionChecker(val context: IrPluginContext) { 9702 to "1.4.0", 9703 to "1.4.1", 9704 to "1.4.2", + 9705 to "1.4.3", ) /** diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt index fa396e40b90..536c711e3a7 100644 --- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt +++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt @@ -28,5 +28,5 @@ internal object ComposeVersion { * IMPORTANT: Whenever updating this value, please make sure to also update `versionTable` and * `minimumRuntimeVersionInt` in `VersionChecker.kt` of the compiler. */ - const val version: Int = 9704 + const val version: Int = 9705 } diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt index 74a02fcf12e..6ceb34fb0ee 100644 --- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt +++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt @@ -275,6 +275,72 @@ class OneDimensionalFocusSearchPreviousTest { } @Test + fun focusMovesToParent() { + // Arrange. + val (parent, child1, child2, child3) = List(4) { mutableStateOf(false) } + rule.setContentForTest { + FocusableBox(parent, 0, 0, 10, 10) { + FocusableBox(child1, 10, 0, 10, 10, initialFocus) + FocusableBox(child2, 20, 0, 10, 10) + FocusableBox(child3, 20, 0, 10, 10) + } + } + + // Act. + val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) } + + // Assert. + rule.runOnIdle { + assertThat(movedFocusSuccessfully).isTrue() + assertThat(parent.value).isTrue() + } + } + + @Test + fun focusMovesToParent_ignoresDeactivated() { + // Arrange. + val (item, parent, child1, child2) = List(4) { mutableStateOf(false) } + rule.setContentForTest { + FocusableBox(item, 0, 0, 10, 10) + FocusableBox(parent, 0, 0, 10, 10, deactivated = true) { + FocusableBox(child1, 10, 0, 10, 10, initialFocus) + FocusableBox(child2, 20, 0, 10, 10) + } + } + + // Act. + val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) } + + // Assert. + rule.runOnIdle { + assertThat(movedFocusSuccessfully).isTrue() + assertThat(item.value).isTrue() + } + } + + @Test + fun focusMovesToParent_ignoresDeactivated_andWrapsAround() { + // Arrange. + val (parent, child1, child2, child3) = List(4) { mutableStateOf(false) } + rule.setContentForTest { + FocusableBox(parent, 0, 0, 10, 10, deactivated = true) { + FocusableBox(child1, 10, 0, 10, 10, initialFocus) + FocusableBox(child2, 20, 0, 10, 10) + FocusableBox(child3, 0, 0, 10, 10) + } + } + + // Act. + val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) } + + // Assert. + rule.runOnIdle { + assertThat(movedFocusSuccessfully).isTrue() + assertThat(child3.value).isTrue() + } + } + + @Test fun focusWrapsAroundToLastItem() { // Arrange. val (item1, item2, item3) = List(3) { mutableStateOf(false) } diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt new file mode 100644 index 00000000000..206c37eb4cf --- /dev/null +++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt @@ -0,0 +1,485 @@ +<<<<<<< HEAD (182910 Merge "Fix 2D focus search issue" into snap-temp-L6200000096) +======= +/* + * Copyright 2023 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.focus + +import androidx.compose.foundation.layout.Box +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester.Companion.Cancel +import androidx.compose.ui.focus.FocusRequester.Companion.Default +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalComposeUiApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class RequestFocusEnterTest { + @get:Rule + val rule = createComposeRule() + + private val focusRequester = FocusRequester() + private var enterTriggered = false + private lateinit var focusState: FocusState + + @Test + fun gainingFocus_doesNotTriggersEnter() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusRequester(focusRequester) + .focusProperties { + enter = { enterTriggered = true; Default } + } + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(enterTriggered).isFalse() + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun gainingFocus_doesNotTriggersEnterForChild() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) { + Box( + Modifier + .focusProperties { + enter = { enterTriggered = true; Default } + } + .focusTarget() + ) + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(enterTriggered).isFalse() + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun gainingFocus_triggersEnterForParent() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusProperties { + enter = { enterTriggered = true; Default } + } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(enterTriggered).isTrue() + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun gainingFocus_triggersEnterForGrandparent() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusProperties { + enter = { enterTriggered = true; Default } + } + .focusTarget() + ) { + Box { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(enterTriggered).isTrue() + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun cancellingFocusGain_usingEnterProperty() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusRequester(focusRequester) + .focusProperties { enter = { Cancel } } + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun cancellingFocusGain_usingEnterPropertyOnChild() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) { + Box(Modifier.focusProperties { enter = { Cancel } }) + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun cancellingFocusGain_usingEnterPropertyOnParent() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusProperties { enter = { Cancel } } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isFalse() + } + } + + @Test + fun cancellingFocusGain_usingEnterPropertyOnGrandparent() { + // Arrange. + rule.setFocusableContent { + Box( + Modifier + .focusProperties { enter = { Cancel } } + .focusTarget() + ) { + Box { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isFalse() + } + } + + @Test + fun cancellingFocusGain_usingACustomDestination() { + // Arrange. + val customDestination = FocusRequester() + rule.setFocusableContent { + Box(Modifier.focusTarget()) { + Box( + Modifier + .focusProperties { enter = { customDestination } } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(focusRequester) + .focusTarget() + ) + Box(Modifier.focusTarget()) + } + Box(Modifier.focusTarget()) { + Box( + Modifier + .focusRequester(customDestination) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isTrue() + } + } + + @Test + fun cancellingFocusGain_usingAChildAsACustomDestination() { + // Arrange. + val customDestination = FocusRequester() + lateinit var destinationFocusState: FocusState + rule.setFocusableContent { + Box( + Modifier + .focusProperties { enter = { customDestination } } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + Box( + Modifier + .focusRequester(customDestination) + .onFocusChanged { destinationFocusState = it } + .focusTarget() + ) + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isFalse() + assertThat(destinationFocusState.isFocused).isTrue() + } + } + + @Test + fun cancellingFocusGain_usingASiblingAsACustomDestination() { + // Arrange. + val customDestination = FocusRequester() + lateinit var destinationFocusState: FocusState + rule.setFocusableContent { + Box( + Modifier + .focusProperties { enter = { customDestination } } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + Box( + Modifier + .focusRequester(customDestination) + .onFocusChanged { destinationFocusState = it } + .focusTarget() + ) + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isFalse() + assertThat(destinationFocusState.isFocused).isTrue() + } + } + + @Test + fun cancellingFocusGain_usingParentAsACustomDestination() { + // Arrange. + val customDestination = FocusRequester() + lateinit var destinationFocusState: FocusState + rule.setFocusableContent { + Box( + Modifier + .focusRequester(customDestination) + .focusProperties { enter = { customDestination } } + .onFocusChanged { destinationFocusState = it } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(focusRequester) + .onFocusChanged { focusState = it } + .focusTarget() + ) + } + } + + // Act. + rule.runOnIdle { + focusRequester.requestFocus() + } + + // Assert. + rule.runOnIdle { + assertThat(focusState.isFocused).isFalse() + assertThat(destinationFocusState.isFocused).isTrue() + } + } + + @Test + fun redirectingFocusRequestOnChild1ToChild2_focusEnterIsCalled() { + // Arrange. + val (initialFocus, child1, child2) = FocusRequester.createRefs() + var enterCount = 0 + rule.setFocusableContent { + Box(Modifier.focusTarget()) { + Box( + Modifier + .focusRequester(initialFocus) + .focusTarget() + ) + Box( + Modifier + .focusProperties { + enter = { + enterCount++ + child2 + } + } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(child1) + .focusTarget() + ) + Box( + Modifier + .focusRequester(child2) + .focusTarget() + ) + } + } + } + rule.runOnIdle { initialFocus.requestFocus() } + + // Act. + rule.runOnIdle { child1.requestFocus() } + + // Assert. + rule.runOnIdle { assertThat(enterCount).isEqualTo(1) } + + // Reset - To ensure that focus enter is called every time we enter. + rule.runOnIdle { + initialFocus.requestFocus() + enterCount = 0 + } + + // Act. + rule.runOnIdle { child1.requestFocus() } + + // Assert. + rule.runOnIdle { assertThat(enterCount).isEqualTo(1) } + } +} +>>>>>>> CHANGE (7a047f Fix Regression in custom enter/exit focus properties) diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusExitTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusExitTest.kt new file mode 100644 index 00000000000..834b2a05168 --- /dev/null +++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusExitTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2023 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.focus + +import androidx.compose.foundation.layout.Box +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalComposeUiApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class RequestFocusExitTest { + @get:Rule + val rule = createComposeRule() + + @Test + fun redirectingFocusExitFromChild1ToChild2_focusExitIsCalled() { + // Arrange. + val (destination, child1, child2) = FocusRequester.createRefs() + var exitCount = 0 + rule.setFocusableContent { + Box(Modifier.focusTarget()) { + Box( + Modifier + .focusRequester(destination) + .focusTarget() + ) + Box( + Modifier + .focusProperties { + exit = { + exitCount++ + child2 + } + } + .focusTarget() + ) { + Box( + Modifier + .focusRequester(child1) + .focusTarget() + ) + Box( + Modifier + .focusRequester(child2) + .focusTarget() + ) + } + } + } + rule.runOnIdle { child1.requestFocus() } + + // Act. + rule.runOnIdle { destination.requestFocus() } + + // Assert. + rule.runOnIdle { assertThat(exitCount).isEqualTo(1) } + + // Reset - To ensure that focus exit is called every time we exit. + rule.runOnIdle { + child1.requestFocus() + exitCount = 0 + } + + // Act. + rule.runOnIdle { destination.requestFocus() } + + // Assert. + rule.runOnIdle { assertThat(exitCount).isEqualTo(1) } + } +} diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt index 57ec4b00b61..27dc28bc545 100644 --- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt +++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt @@ -93,6 +93,63 @@ class FocusTargetModifierNode : ObserverNode, ModifierLocalNode, Modifier.Node() return properties } +<<<<<<< HEAD (182910 Merge "Fix 2D focus search issue" into snap-temp-L6200000096) +======= + /** + * Fetch custom enter destination associated with this [focusTarget]. + * + * Custom focus enter properties are specified as a lambda. If the user runs code in this + * lambda that triggers a focus search, or some other focus change that causes focus to leave + * the sub-hierarchy associated with this node, we could end up in a loop as that operation + * will trigger another invocation of the lambda associated with the focus exit property. + * This function prevents that re-entrant scenario by ensuring there is only one concurrent + * invocation of this lambda. + */ + @OptIn(ExperimentalComposeUiApi::class) + internal inline fun fetchCustomEnter( + focusDirection: FocusDirection, + block: (FocusRequester) -> Unit + ) { + if (!isProcessingCustomEnter) { + isProcessingCustomEnter = true + try { + fetchFocusProperties().enter(focusDirection).also { + if (it !== Default) block(it) + } + } finally { + isProcessingCustomEnter = false + } + } + } + + /** + * Fetch custom exit destination associated with this [focusTarget]. + * + * Custom focus exit properties are specified as a lambda. If the user runs code in this + * lambda that triggers a focus search, or some other focus change that causes focus to leave + * the sub-hierarchy associated with this node, we could end up in a loop as that operation + * will trigger another invocation of the lambda associated with the focus exit property. + * This function prevents that re-entrant scenario by ensuring there is only one concurrent + * invocation of this lambda. + */ + @OptIn(ExperimentalComposeUiApi::class) + internal inline fun fetchCustomExit( + focusDirection: FocusDirection, + block: (FocusRequester) -> Unit + ) { + if (!isProcessingCustomExit) { + isProcessingCustomExit = true + try { + fetchFocusProperties().exit(focusDirection).also { + if (it !== Default) block(it) + } + } finally { + isProcessingCustomExit = false + } + } + } + +>>>>>>> CHANGE (7a047f Fix Regression in custom enter/exit focus properties) internal fun invalidateFocus() { when (focusState) { // Clear focus from the current FocusTarget. diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt index 70b237cffa6..d19c5431826 100644 --- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt +++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt @@ -71,10 +71,9 @@ private fun FocusTargetModifierNode.backwardFocusSearch( // Unlike forwardFocusSearch, backwardFocusSearch visits the children before the parent. when (focusedChild.focusStateImpl) { - ActiveParent -> - focusedChild.backwardFocusSearch(onFound) || + ActiveParent -> focusedChild.backwardFocusSearch(onFound) || generateAndSearchChildren(focusedChild, Previous, onFound) || - (fetchFocusProperties().canFocus && onFound.invoke(focusedChild)) + (focusedChild.fetchFocusProperties().canFocus && onFound.invoke(focusedChild)) // Since this item "is focused", it means we already visited all its children. // So just search among its siblings. diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt index ad9109fac66..dc0befb5284 100644 --- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt +++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt @@ -212,6 +212,8 @@ private fun DelegatableNode.collectAccessibleChildren( accessibleChildren: MutableVector<FocusTargetModifierNode> ) { visitSubtreeIf(Nodes.FocusTarget) { + // TODO(b/278765590): Find the root issue why visitChildren returns unattached nodes. + if (!it.isAttached) return@visitSubtreeIf false if (it.fetchFocusProperties().canFocus) { accessibleChildren.add(it) 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 46ae3ed096c..0c7faa9b8aa 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 @@ -411,7 +411,7 @@ internal class LayoutNode( mLookaheadScope = parent?.mLookaheadScope ?: if (isLookaheadRoot) LookaheadScope(this) else null - nodes.attach(performInvalidations = false) + nodes.attach() _foldedChildren.forEach { child -> child.attach(owner) } @@ -1379,7 +1379,7 @@ internal class LayoutNode( resetModifierState() } // resetModifierState detaches all nodes, so we need to re-attach them upon reuse. - nodes.attach(true) + nodes.attach() } override fun onDeactivate() { 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 e6eeda92dc1..5684882ca77 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 @@ -213,7 +213,7 @@ internal class NodeChain(val layoutNode: LayoutNode) { syncCoordinators() } if (attachNeeded && layoutNode.isAttached) { - attach(performInvalidations = true) + attach() } } @@ -264,17 +264,15 @@ internal class NodeChain(val layoutNode: LayoutNode) { outerCoordinator = coordinator } - fun attach(performInvalidations: Boolean) { + fun attach() { headToTail { if (!it.isAttached) { it.attach() - if (performInvalidations) { - if (it.insertedNodeAwaitingAttachForInvalidation) { - autoInvalidateInsertedNode(it) - } - if (it.updatedNodeAwaitingAttachForInvalidation) { - autoInvalidateUpdatedNode(it) - } + if (it.insertedNodeAwaitingAttachForInvalidation) { + autoInvalidateInsertedNode(it) + } + if (it.updatedNodeAwaitingAttachForInvalidation) { + autoInvalidateUpdatedNode(it) } // when we attach with performInvalidations == false no separate // invalidations needed as the whole LayoutNode is attached to the tree. diff --git a/libraryversions.toml b/libraryversions.toml index 0b6c8036395..cc31d626832 100644 --- a/libraryversions.toml +++ b/libraryversions.toml @@ -22,7 +22,7 @@ CARDVIEW = "1.1.0-alpha01" CAR_APP = "1.4.0-alpha01" COLLECTION = "1.3.0-alpha03" COLLECTION_KMP = "1.3.0-dev01" -COMPOSE = "1.4.2" +COMPOSE = "1.4.3" COMPOSE_COMPILER = "1.4.3" COMPOSE_MATERIAL3 = "1.1.0-alpha07" COMPOSE_RUNTIME_TRACING = "1.0.0-alpha03" diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt index cec085f3880..51f87fd09fb 100644 --- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt +++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/list/LazyListTest.kt @@ -84,7 +84,6 @@ import com.google.common.truth.Truth.assertWithMessage import java.util.concurrent.CountDownLatch import kotlin.math.roundToInt import kotlinx.coroutines.runBlocking -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -813,7 +812,6 @@ class LazyListTest(orientation: Orientation) : BaseLazyListTestWithOrientation(o } } - @Ignore // b/268211857 @Test fun scroll_makeListSmaller_scroll() { var items by mutableStateOf((1..100).toList()) |