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