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)
+ }
+}