Add Fragment.content extension

Provides an easy integration for providing Compose content inside of a
Fragment that sets the ComposeView and ViewCompositionStrategy.

RelNote: "The new Fragment Compose module provides a Fragment.content
extension function to handle setting a Fragment's view in Compose."
Test: added test
Bug: 258046948

Change-Id: Ia166527918517593e94bcae239ff714df4dc00ad
diff --git a/fragment/fragment-compose/api/current.txt b/fragment/fragment-compose/api/current.txt
index e6f50d0..6c501a4 100644
--- a/fragment/fragment-compose/api/current.txt
+++ b/fragment/fragment-compose/api/current.txt
@@ -1 +1,9 @@
 // Signature format: 4.0
+package androidx.fragment.compose {
+
+  public final class FragmentKt {
+    method public static androidx.compose.ui.platform.ComposeView content(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+}
+
diff --git a/fragment/fragment-compose/api/restricted_current.txt b/fragment/fragment-compose/api/restricted_current.txt
index e6f50d0..6c501a4 100644
--- a/fragment/fragment-compose/api/restricted_current.txt
+++ b/fragment/fragment-compose/api/restricted_current.txt
@@ -1 +1,9 @@
 // Signature format: 4.0
+package androidx.fragment.compose {
+
+  public final class FragmentKt {
+    method public static androidx.compose.ui.platform.ComposeView content(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+}
+
diff --git a/fragment/fragment-compose/build.gradle b/fragment/fragment-compose/build.gradle
index cb5cf0d..9599d13 100644
--- a/fragment/fragment-compose/build.gradle
+++ b/fragment/fragment-compose/build.gradle
@@ -21,37 +21,32 @@
  * Please use that script when creating a new project, rather than copying an existing project and
  * modifying its settings.
  */
-import androidx.build.LibraryType
-import androidx.build.PlatformIdentifier
 import androidx.build.Publish
+import androidx.build.RunApiTasks
+import androidx.build.LibraryType
+
 
 plugins {
     id("AndroidXPlugin")
     id("AndroidXComposePlugin")
     id("com.android.library")
+    id("org.jetbrains.kotlin.android")
 }
 
-androidXMultiplatform {
-    android()
+dependencies {
 
-    defaultPlatform(PlatformIdentifier.ANDROID)
+    implementation(libs.kotlinStdlib)
+    api(project(":fragment:fragment-ktx"))
+    api("androidx.compose.runtime:runtime:1.5.4")
+    api("androidx.compose.ui:ui:1.5.4")
 
-    sourceSets {
-        androidMain {
-            dependencies {
-                api(project(":fragment:fragment-ktx"))
-            }
-        }
-
-        androidInstrumentedTest {
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-    }
+    androidTestImplementation project(":compose:ui:ui-test-junit4")
+    androidTestImplementation project(":compose:material:material")
+    androidTestImplementation project(":compose:test-utils")
+    androidTestImplementation(libs.testRules)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.junit)
+    androidTestImplementation(libs.truth)
 }
 
 android {
diff --git a/fragment/fragment-compose/src/androidTest/AndroidManifest.xml b/fragment/fragment-compose/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..1c038a4
--- /dev/null
+++ b/fragment/fragment-compose/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <application>
+    <activity android:name="androidx.fragment.compose.test.TestActivity" />
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/FragmentTest.kt b/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/FragmentTest.kt
new file mode 100644
index 0000000..a9d39ff
--- /dev/null
+++ b/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/FragmentTest.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.fragment.compose
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.compose.material.Text
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.commitNow
+import androidx.fragment.compose.test.TestActivity
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class FragmentTest {
+    @get:Rule
+    val testRule = createAndroidComposeRule<TestActivity>()
+
+    @Test
+    fun showContent() {
+        val fm = testRule.activity.supportFragmentManager
+        testRule.runOnUiThread {
+            fm.commitNow {
+                add(androidx.fragment.compose.test.R.id.fragment_container, MyFragment())
+            }
+        }
+
+        testRule.waitForIdle()
+
+        testRule.onNodeWithText("MyFragment").assertIsDisplayed()
+    }
+}
+
+class MyFragment : Fragment() {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ) = content {
+        Text("MyFragment")
+    }
+}
diff --git a/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/test/TestActivity.kt b/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/test/TestActivity.kt
new file mode 100644
index 0000000..ef92ecf
--- /dev/null
+++ b/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/test/TestActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.fragment.compose.test
+
+import androidx.fragment.app.FragmentActivity
+
+class TestActivity : FragmentActivity(R.layout.activity_main)
diff --git a/fragment/fragment-compose/src/androidTest/res/layout/activity_main.xml b/fragment/fragment-compose/src/androidTest/res/layout/activity_main.xml
new file mode 100644
index 0000000..e22d691
--- /dev/null
+++ b/fragment/fragment-compose/src/androidTest/res/layout/activity_main.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+
+<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fragment_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</androidx.fragment.app.FragmentContainerView>
\ No newline at end of file
diff --git a/fragment/fragment-compose/src/main/java/androidx/fragment/compose/Fragment.kt b/fragment/fragment-compose/src/main/java/androidx/fragment/compose/Fragment.kt
new file mode 100644
index 0000000..ccdd0a9
--- /dev/null
+++ b/fragment/fragment-compose/src/main/java/androidx/fragment/compose/Fragment.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.fragment.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.fragment.app.Fragment
+
+/**
+ * Wrapper function that handles the setup for creating a custom Fragment that hosts Compose
+ * content. It automatically sets the [ViewCompositionStrategy] to
+ * [ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed].
+ *
+ * It should be used as part of the implementation of [Fragment.onCreateView] and requires a context
+ * meaning the fragment must be attached to a FragmentManager.
+ *
+ * ```
+ * class ExampleFragment : Fragment() {
+ *     override fun onCreateView(
+ *         inflater: LayoutInflater,
+ *         container: ViewGroup?,
+ *         savedInstanceState: Bundle?
+ *     ) = content {
+ *         val viewModel: ExampleViewModel = viewModel()
+ *         // put your @Composable content here
+ *     }
+ * }
+ * ```
+ */
+fun Fragment.content(content: @Composable () -> Unit): ComposeView {
+    return ComposeView(requireContext()).apply {
+        setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+        setContent(content)
+    }
+}