Protect AndroidComposeView from exceptionally large sizes
Fixes: 347036173
When the AndroidComposeView receives sizes too large to fit
into constraints, they now are forced to fit within Constraints.
Test: new tests
(cherry picked from https://android-review.googlesource.com/q/commit:3d4d9824c3bd58a622ba12c1dfac33e798c16fb1)
Merged-In: I28b34f0168c9e9b3e503f6e8180a72b3501107ac
Change-Id: I28b34f0168c9e9b3e503f6e8180a72b3501107ac
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ComposeViewLayoutTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ComposeViewLayoutTest.kt
new file mode 100644
index 0000000..728f23b
--- /dev/null
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ComposeViewLayoutTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.layout
+
+import android.view.ViewGroup.LayoutParams
+import android.widget.HorizontalScrollView
+import android.widget.ScrollView
+import androidx.activity.ComponentActivity
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class ComposeViewLayoutTest {
+ @get:Rule val rule = createAndroidComposeRule()
+
+ @Test
+ fun largeWidth() {
+ var width by mutableStateOf(0)
+ var height by mutableStateOf(0)
+ rule.setContent {
+ AndroidView(
+ factory = { context ->
+ HorizontalScrollView(context).also { scrollView ->
+ scrollView.addView(
+ ComposeView(context).also { view ->
+ view.setContent {
+ with(LocalDensity.current) {
+ Box(
+ Modifier.fillMaxHeight().width(2000.toDp()).onPlaced {
+ coordinates ->
+ width = coordinates.size.width
+ height = coordinates.size.height
+ }
+ )
+ }
+ }
+ view.layoutParams = LayoutParams(1 shl 28, 2000)
+ }
+ )
+ }
+ }
+ )
+ }
+
+ rule.runOnIdle {
+ assertThat(width).isEqualTo(2000)
+ assertThat(height).isEqualTo(2000)
+ }
+ }
+
+ @Test
+ fun largeHeight() {
+ var width by mutableStateOf(0)
+ var height by mutableStateOf(0)
+ rule.setContent {
+ AndroidView(
+ factory = { context ->
+ ScrollView(context).also { scrollView ->
+ scrollView.addView(
+ ComposeView(context).also { view ->
+ view.setContent {
+ with(LocalDensity.current) {
+ Box(
+ Modifier.fillMaxWidth().height(2000.toDp()).onPlaced {
+ coordinates ->
+ width = coordinates.size.width
+ height = coordinates.size.height
+ }
+ )
+ }
+ }
+ view.layoutParams = LayoutParams(2000, 1 shl 28)
+ }
+ )
+ }
+ }
+ )
+ }
+
+ rule.runOnIdle {
+ assertThat(width).isEqualTo(2000)
+ assertThat(height).isEqualTo(2000)
+ }
+ }
+}
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 f394a4a..edc3203 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
@@ -1356,7 +1356,13 @@
val (minWidth, maxWidth) = convertMeasureSpec(widthMeasureSpec)
val (minHeight, maxHeight) = convertMeasureSpec(heightMeasureSpec)
- val constraints = Constraints(minWidth, maxWidth, minHeight, maxHeight)
+ val constraints =
+ Constraints.fitPrioritizingHeight(
+ minWidth = minWidth,
+ maxWidth = maxWidth,
+ minHeight = minHeight,
+ maxHeight = maxHeight
+ )
if (onMeasureConstraints == null) {
// first onMeasure after last onLayout
onMeasureConstraints = constraints