aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-16 22:48:32 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-03-16 22:48:32 +0000
commit5c52e350f924e5e7b0d110a5ea342c5fd6b249f0 (patch)
treee8a55bda1ffeb7472fcaad0385c2e07873d47a06
parent8b6d82fa81cf938a709c55cc97db95c16f0d5715 (diff)
parent1b33968f14a21185a5b29b2cc0785125dbbd9066 (diff)
downloadsupport-5c52e350f924e5e7b0d110a5ea342c5fd6b249f0.tar.gz
Merge "Fix NPE in AndroidView when in a SubcomposeLayout" into snap-temp-L01600000959187804
-rw-r--r--compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt37
-rw-r--r--compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt13
2 files changed, 49 insertions, 1 deletions
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
index 71f542b250b..925bd713b52 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
@@ -18,6 +18,7 @@ package androidx.compose.ui.layout
import android.annotation.SuppressLint
import android.os.Build
+import android.view.View
import android.widget.FrameLayout
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
@@ -52,6 +53,7 @@ import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asAndroidBitmap
+import androidx.compose.ui.layout.RootMeasurePolicy.measure
import androidx.compose.ui.platform.AndroidOwnerExtraAssertionsRule
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalDensity
@@ -71,6 +73,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.zIndex
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
@@ -2351,6 +2354,40 @@ class SubcomposeLayoutTest {
.assertExists()
}
+ // Regression test of b/271156218
+ @Test
+ fun deactivatingDeeplyNestedAndroidViewDoesNotCauseRemeasure() {
+ var showContent by mutableStateOf(true)
+ val state = SubcomposeLayoutState(SubcomposeSlotReusePolicy(1))
+ rule.setContent {
+ SubcomposeLayout(
+ state = state,
+ modifier = Modifier.fillMaxSize()
+ ) { constraints ->
+ val content = if (showContent) {
+ subcompose(0) {
+ Box {
+ AndroidView(::View, Modifier.fillMaxSize().testTag("AndroidView"))
+ }
+ }
+ } else emptyList()
+
+ val placeables = measure(content, constraints)
+ layout(100, 100) {
+ placeables.placeChildren()
+ }
+ }
+ }
+
+ rule.onNodeWithTag("AndroidView").assertExists()
+
+ rule.runOnIdle { showContent = false }
+ rule.onNodeWithTag("AndroidView").assertIsNotDisplayed()
+
+ rule.runOnIdle { showContent = true }
+ rule.onNodeWithTag("AndroidView").assertExists()
+ }
+
private fun composeItems(
state: SubcomposeLayoutState,
items: MutableState<List<Int>>
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
index 258b7171ea5..bd6bf08f5f6 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
@@ -204,7 +204,7 @@ internal open class AndroidViewHolder(
override fun onDeactivate() {
reset()
- removeView(view)
+ removeAllViewsInLayout()
}
override fun onRelease() {
@@ -212,6 +212,13 @@ internal open class AndroidViewHolder(
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ if (view?.parent !== this) {
+ setMeasuredDimension(
+ MeasureSpec.getSize(widthMeasureSpec),
+ MeasureSpec.getSize(heightMeasureSpec)
+ )
+ return
+ }
view?.measure(widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(view?.measuredWidth ?: 0, view?.measuredHeight ?: 0)
lastWidthMeasureSpec = widthMeasureSpec
@@ -339,6 +346,10 @@ internal open class AndroidViewHolder(
measurables: List<Measurable>,
constraints: Constraints
): MeasureResult {
+ if (childCount == 0) {
+ return layout(constraints.minWidth, constraints.minHeight) {}
+ }
+
if (constraints.minWidth != 0) {
getChildAt(0).minimumWidth = constraints.minWidth
}