Merge "Removes Appcompat and Fragment dependencies from compose:ui:ui" into androidx-main am: d192917993

Original change: https://android-review.googlesource.com/c/platform/frameworks/support/+/1603516

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I4a00eb72e7acae366c39bebacdb7740372aedc9f
diff --git a/activity/activity-compose/src/main/java/androidx/activity/compose/ComponentActivity.kt b/activity/activity-compose/src/main/java/androidx/activity/compose/ComponentActivity.kt
index 9516dd8..3e09abe 100644
--- a/activity/activity-compose/src/main/java/androidx/activity/compose/ComponentActivity.kt
+++ b/activity/activity-compose/src/main/java/androidx/activity/compose/ComponentActivity.kt
@@ -21,12 +21,16 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionContext
 import androidx.compose.ui.platform.ComposeView
+import androidx.lifecycle.ViewTreeLifecycleOwner
+import androidx.lifecycle.ViewTreeViewModelStoreOwner
+import androidx.savedstate.ViewTreeSavedStateRegistryOwner
 
 /**
  * Composes the given composable into the given activity. The [content] will become the root view
  * of the given activity.
  *
- * This is roughly equivalent to calling [setContentView] with a [ComposeView] i.e.:
+ * This is roughly equivalent to calling [ComponentActivity.setContentView] with a [ComposeView]
+ * i.e.:
  *
  * ```
  * setContentView(
@@ -57,6 +61,9 @@
         // to have ComposeView create the composition on attach
         setParentCompositionContext(parent)
         setContent(content)
+        // Set the view tree owners before setting the content view so that the inflation process
+        // and attach listeners will see them already present
+        setOwners()
         setContentView(this, DefaultActivityContentLayoutParams)
     }
 }
@@ -65,3 +72,20 @@
     ViewGroup.LayoutParams.WRAP_CONTENT,
     ViewGroup.LayoutParams.WRAP_CONTENT
 )
+
+/**
+ * These owners are not set before AppCompat 1.3+ due to a bug, so we need to set them manually in
+ * case developers are using an older version of AppCompat.
+ */
+private fun ComponentActivity.setOwners() {
+    val decorView = window.decorView
+    if (ViewTreeLifecycleOwner.get(decorView) == null) {
+        ViewTreeLifecycleOwner.set(decorView, this)
+    }
+    if (ViewTreeViewModelStoreOwner.get(decorView) == null) {
+        ViewTreeViewModelStoreOwner.set(decorView, this)
+    }
+    if (ViewTreeSavedStateRegistryOwner.get(decorView) == null) {
+        ViewTreeSavedStateRegistryOwner.set(decorView, this)
+    }
+}
diff --git a/compose/material/material-icons-extended/build.gradle b/compose/material/material-icons-extended/build.gradle
index d1d0196..8808af5 100644
--- a/compose/material/material-icons-extended/build.gradle
+++ b/compose/material/material-icons-extended/build.gradle
@@ -56,6 +56,7 @@
         androidTestImplementation(project(":test-screenshot"))
         androidTestImplementation(project(":compose:ui:ui-test-junit4"))
         androidTestImplementation(project(":activity:activity-compose"))
+        androidTestImplementation("androidx.appcompat:appcompat:1.3.0-beta01")
     }
 }
 
@@ -81,6 +82,7 @@
                 implementation(project(":test-screenshot"))
                 implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(project(":activity:activity-compose"))
+                implementation("androidx.appcompat:appcompat:1.3.0-beta01")
 
                 implementation(ANDROIDX_TEST_RULES)
                 implementation(ANDROIDX_TEST_RUNNER)
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 996054c..a4de7229 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -62,12 +62,9 @@
         implementation("androidx.autofill:autofill:1.0.0")
         implementation(KOTLIN_COROUTINES_ANDROID)
 
-        // we don't use these dependencies but we need to ensure at least these versions are
-        // used if the user adds these dependencies as otherwise AppCompatActivity and Fragment
-        // will not propagate ViewTree*Owners we are relying on and we will crash.
-        // TODO: remove these dependencies at some point: b/161814404
-        implementation("androidx.fragment:fragment:1.3.0")
-        implementation("androidx.appcompat:appcompat:1.3.0-beta01")
+        implementation("androidx.savedstate:savedstate:1.1.0")
+        implementation("androidx.lifecycle:lifecycle-runtime:2.3.0")
+        implementation("androidx.lifecycle:lifecycle-viewmodel:2.3.0")
 
         testImplementation(ANDROIDX_TEST_RULES)
         testImplementation(ANDROIDX_TEST_RUNNER)
@@ -82,8 +79,6 @@
         testImplementation(project(":compose:ui:ui-test-junit4"))
         testImplementation(project(":compose:test-utils"))
 
-        androidTestImplementation("androidx.fragment:fragment:1.3.0")
-        androidTestImplementation("androidx.appcompat:appcompat:1.1.0")
         androidTestImplementation(ANDROIDX_TEST_UIAUTOMATOR)
         androidTestImplementation(ANDROIDX_TEST_RULES)
         androidTestImplementation(ANDROIDX_TEST_RUNNER)
@@ -108,6 +103,8 @@
         androidTestImplementation("androidx.recyclerview:recyclerview:1.1.0")
         androidTestImplementation("androidx.core:core-ktx:1.1.0")
         androidTestImplementation(project(":activity:activity-compose"))
+        androidTestImplementation("androidx.appcompat:appcompat:1.3.0-beta01")
+        androidTestImplementation("androidx.fragment:fragment:1.3.0")
 
         lintChecks(project(":compose:ui:ui-lint"))
         lintPublish(project(":compose:ui:ui-lint"))
@@ -151,12 +148,9 @@
                 implementation("androidx.autofill:autofill:1.0.0")
                 implementation(KOTLIN_COROUTINES_ANDROID)
 
-                // we don't use these dependencies but we need to ensure at least these versions are
-                // used if the user adds these dependencies as otherwise AppCompatActivity and Fragment
-                // will not propagate ViewTree*Owners we are relying on and we will crash.
-                // TODO: remove these dependencies at some point: b/161814404
-                implementation("androidx.fragment:fragment:1.3.0")
-                implementation("androidx.appcompat:appcompat:1.3.0-beta01")
+                implementation("androidx.savedstate:savedstate:1.1.0")
+                implementation("androidx.lifecycle:lifecycle-runtime:2.3.0")
+                implementation("androidx.lifecycle:lifecycle-viewmodel:2.3.0")
             }
 
             jvmMain.dependencies {
@@ -188,7 +182,7 @@
 
             androidAndroidTest.dependencies {
                 implementation("androidx.fragment:fragment:1.3.0")
-                implementation("androidx.appcompat:appcompat:1.1.0")
+                implementation("androidx.appcompat:appcompat:1.3.0-beta01")
                 implementation(ANDROIDX_TEST_UIAUTOMATOR)
                 implementation(ANDROIDX_TEST_RULES)
                 implementation(ANDROIDX_TEST_RUNNER)
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
index a88c480..a2c74d0 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
@@ -29,6 +29,7 @@
 import androidx.compose.ui.node.Owner
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.ViewTreeLifecycleOwner
+import androidx.savedstate.ViewTreeSavedStateRegistryOwner
 
 /**
  * Base class for custom [android.view.View]s implemented using Jetpack Compose UI.
@@ -203,6 +204,20 @@
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
 
+        val message = "If you are adding this ComposeView to an AppCompatActivity, make sure you " +
+            "are using AppCompat version 1.3+. If you are adding this ComposeView to a " +
+            "Fragment, make sure you are using Fragment version 1.3+. For other cases, manually " +
+            "set owners on this view by using `ViewTreeLifecycleOwner.set()` and " +
+            "`ViewTreeSavedStateRegistryOwner.set()`."
+        checkNotNull(ViewTreeLifecycleOwner.get(this)) {
+            "ViewTreeLifecycleOwner not set for this ComposeView. $message"
+        }
+        checkNotNull(ViewTreeSavedStateRegistryOwner.get(this)) {
+            "ViewTreeSavedStateRegistryOwner not set for this ComposeView. $message"
+        }
+        // Not checking for ViewTreeViewModelStoreOwner as we don't need it inside Compose, but we
+        // provide it in ComponentActivity.setContent for convenience.
+
         if (shouldCreateCompositionOnAttachedToWindow) {
             ensureCompositionCreated()
         }
diff --git a/lifecycle/lifecycle-viewmodel-compose/build.gradle b/lifecycle/lifecycle-viewmodel-compose/build.gradle
index f914120..f546dff 100644
--- a/lifecycle/lifecycle-viewmodel-compose/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-compose/build.gradle
@@ -44,7 +44,7 @@
     androidTestImplementation(JUNIT)
     androidTestImplementation(TRUTH)
     androidTestImplementation "androidx.fragment:fragment:1.3.0"
-    androidTestImplementation "androidx.appcompat:appcompat:1.1.0"
+    androidTestImplementation "androidx.appcompat:appcompat:1.3.0-beta01"
     androidTestImplementation projectOrArtifact(":activity:activity-compose")
 }