Collect ReduceMotion setting changes in lifecycle aware manner

Bug: 314722367
Test: Manual

Change-Id: I249c0c0a1c8c47493954e89bf12047a32102b95e
diff --git a/wear/compose/compose-foundation/build.gradle b/wear/compose/compose-foundation/build.gradle
index 71f1302..214a3f6 100644
--- a/wear/compose/compose-foundation/build.gradle
+++ b/wear/compose/compose-foundation/build.gradle
@@ -33,6 +33,7 @@
     implementation(libs.kotlinStdlib)
     implementation(project(":compose:foundation:foundation-layout"))
     implementation(project(":compose:ui:ui-util"))
+    implementation(project(":lifecycle:lifecycle-runtime-compose"))
     implementation("androidx.core:core:1.11.0")
     implementation("androidx.profileinstaller:profileinstaller:1.3.0")
 
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CompositionLocals.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CompositionLocals.kt
index 03c26c6..6c6eb62 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CompositionLocals.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CompositionLocals.kt
@@ -29,13 +29,13 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.LocalContext
 import androidx.core.os.HandlerCompat
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import java.util.concurrent.atomic.AtomicReference
 import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
+import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.stateIn
 
 /**
@@ -48,7 +48,8 @@
 val LocalReduceMotion: ProvidableCompositionLocal = staticCompositionLocalOf {
     ReduceMotion {
         val context = LocalContext.current.applicationContext
-        getReduceMotionFlowFor(context).value
+        val flow = getReduceMotionFlowFor(context)
+        flow.collectAsStateWithLifecycle().value
     }
 }
 
@@ -85,27 +86,34 @@
 private fun getReduceMotionFlowFor(applicationContext: Context): StateFlow {
     val resolver = applicationContext.contentResolver
     val reduceMotionUri = Settings.Global.getUriFor(REDUCE_MOTION)
-    val channel = Channel(CONFLATED)
-    val contentObserver =
-        object : ContentObserver(HandlerCompat.createAsync(Looper.getMainLooper())) {
-            override fun onChange(selfChange: Boolean, uri: Uri?) {
-                channel.trySend(Unit)
-            }
-        }
+
     return reduceMotionCache.updateAndGet {
-        it ?: flow {
-            resolver.registerContentObserver(reduceMotionUri, false, contentObserver)
-            try {
-                for (value in channel) {
-                    val newValue = getReducedMotionSettingValue(resolver)
-                    emit(newValue)
+        it ?: callbackFlow {
+            val contentObserver =
+                object : ContentObserver(HandlerCompat.createAsync(Looper.getMainLooper())) {
+                    override fun deliverSelfNotifications(): Boolean {
+                        // Returning true to receive change notification so that
+                        // the flow sends new value after it is initialized.
+                        return true
+                    }
+
+                    override fun onChange(selfChange: Boolean, uri: Uri?) {
+                        super.onChange(selfChange, uri)
+                        trySend(getReducedMotionSettingValue(resolver))
+                    }
                 }
-            } finally {
+
+            resolver.registerContentObserver(reduceMotionUri, false, contentObserver)
+
+            // Force send value when flow is initialized
+            resolver.notifyChange(reduceMotionUri, contentObserver)
+
+            awaitClose {
                 resolver.unregisterContentObserver(contentObserver)
             }
         }.stateIn(
             MainScope(),
-            SharingStarted.WhileSubscribed(),
+            SharingStarted.WhileSubscribed(5000),
             getReducedMotionSettingValue(resolver)
         )
     }
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
index 64ad508..24f6946 100644
--- a/wear/compose/integration-tests/demos/build.gradle
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -69,6 +69,9 @@
     androidTestImplementation(project(":activity:activity-compose"))
     androidTestImplementation(project(":activity:activity-ktx"))
     androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+    androidTestImplementation(project(":lifecycle:lifecycle-runtime"))
+    androidTestImplementation(project(":lifecycle:lifecycle-common"))
+    androidTestImplementation(project(":lifecycle:lifecycle-runtime-ktx"))
     androidTestImplementation(libs.testCore)
     androidTestImplementation(libs.testRules)
     androidTestImplementation(libs.testRunner)
diff --git a/wear/compose/integration-tests/navigation/build.gradle b/wear/compose/integration-tests/navigation/build.gradle
index 065c152..dc4e776 100644
--- a/wear/compose/integration-tests/navigation/build.gradle
+++ b/wear/compose/integration-tests/navigation/build.gradle
@@ -52,12 +52,8 @@
     implementation(project(":wear:compose:compose-foundation-samples"))
     implementation(project(":wear:compose:compose-material-samples"))
     implementation(project(':wear:compose:compose-navigation'))
-    // old version of common-java8 conflicts with newer version, because both have
-    // DefaultLifecycleEventObserver.
-    // Outside of androidx this is resolved via constraint added to lifecycle-common,
-    // but it doesn't work in androidx.
-    // See aosp/1804059
-    androidTestImplementation "androidx.lifecycle:lifecycle-common-java8:2.4.0"
+
+    androidTestImplementation(project(":lifecycle:lifecycle-common"))
     // Uses project dependency to match collections/compose-runtime
     androidTestImplementation api("androidx.annotation:annotation:1.7.0")
 }
\ No newline at end of file