Add ReduceMotion support for Dialogs, Confirmations and OpenOnPhoneDialog

Bug: 378683095
Test: Manually verified
Change-Id: I2b2ab0f13743453e04aea5f1c21c21a05929af46
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt
index ef59b1a..2a17737 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt
@@ -28,6 +28,7 @@
 import androidx.compose.animation.core.TwoWayConverter
 import androidx.compose.animation.core.VectorizedAnimationSpec
 import androidx.compose.runtime.withFrameMillis
+import kotlinx.coroutines.delay
 
 /**
  * Returns a new [AnimationSpec] that is a faster version of this one.
@@ -169,4 +170,11 @@
     return
 }
 
+/** Delay to be used for animations. Will enable delay only when ReducedMotion is disabled. */
+internal suspend fun animatedDelay(duration: Long, reduceMotionEnabled: Boolean) {
+    if (!reduceMotionEnabled) {
+        delay(duration)
+    }
+}
+
 private const val MAX_WAIT_TIME_MILLIS = 1_000L
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Confirmation.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Confirmation.kt
index 6bfc308..310e831 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Confirmation.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Confirmation.kt
@@ -61,6 +61,7 @@
 import androidx.wear.compose.foundation.CurvedModifier
 import androidx.wear.compose.foundation.CurvedScope
 import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.LocalReduceMotion
 import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.material3.tokens.ColorSchemeKeyTokens
 import androidx.wear.compose.material3.tokens.MotionTokens.DurationShort2
@@ -191,6 +192,7 @@
         }
     }
 
+    val reduceMotionEnabled = LocalReduceMotion.current.enabled()
     Dialog(
         show = show,
         modifier = modifier,
@@ -200,7 +202,7 @@
         val alphaAnimatable = remember { Animatable(0f) }
         val textOpacityAnimationSpec = TextOpacityAnimationSpec
         LaunchedEffect(Unit) {
-            delay(DurationShort2.toLong())
+            animatedDelay(DurationShort2.toLong(), reduceMotionEnabled)
             alphaAnimatable.animateTo(1f, textOpacityAnimationSpec)
         }
 
@@ -353,8 +355,10 @@
         durationMillis = durationMillis,
     ) {
         val translationXAnimatable = remember { Animatable(FailureContentTransition[0]) }
+        val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
         LaunchedEffect(Unit) {
-            delay(DurationShort3.toLong())
+            animatedDelay(DurationShort3.toLong(), reduceMotionEnabled)
             translationXAnimatable.animateTo(
                 FailureContentTransition[1],
                 FailureContentAnimationSpecs[0]
@@ -405,8 +409,10 @@
         val animation =
             AnimatedImageVector.animatedVectorResource(R.drawable.wear_m3c_check_animation)
         var atEnd by remember { mutableStateOf(false) }
+        val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
         LaunchedEffect(Unit) {
-            delay(IconDelay)
+            animatedDelay(IconDelay, reduceMotionEnabled)
             atEnd = true
         }
         Icon(
@@ -425,8 +431,10 @@
         val animation =
             AnimatedImageVector.animatedVectorResource(R.drawable.wear_m3c_failure_animation)
         var atEnd by remember { mutableStateOf(false) }
+        val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
         LaunchedEffect(Unit) {
-            delay(IconDelay)
+            animatedDelay(IconDelay, reduceMotionEnabled)
             atEnd = true
         }
         Icon(
@@ -662,8 +670,10 @@
     ) {
         val alphaAnimatable = remember { Animatable(0f) }
         val textOpacityAnimationSpec = TextOpacityAnimationSpec
+        val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
         LaunchedEffect(Unit) {
-            delay(DurationShort2.toLong())
+            animatedDelay(DurationShort2.toLong(), reduceMotionEnabled)
             alphaAnimatable.animateTo(1f, textOpacityAnimationSpec)
         }
         Box(modifier = Modifier.fillMaxSize()) {
@@ -705,8 +715,10 @@
         MaterialTheme.motionScheme.defaultSpatialSpec()
     val heroShapeRotationAnimationSpec: AnimationSpec<Float> =
         MaterialTheme.motionScheme.slowEffectsSpec()
+    val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
     LaunchedEffect(Unit) {
-        delay(DurationShort2.toLong())
+        animatedDelay(DurationShort2.toLong(), reduceMotionEnabled)
         launch { shapeAnimatable.animateTo(1f, heroShapeMorphAnimationSpec) }
         rotateAnimatable.animateTo(0f, heroShapeRotationAnimationSpec)
     }
@@ -728,9 +740,10 @@
 
     val targetHeight = screenHeightDp() * SuccessHeightFraction.toFloat()
     val heightAnimatable = remember { Animatable(width) }
+    val reduceMotionEnabled = LocalReduceMotion.current.enabled()
 
     LaunchedEffect(Unit) {
-        delay(DurationShort2.toLong())
+        animatedDelay(DurationShort2.toLong(), reduceMotionEnabled)
         heightAnimatable.animateTo(targetHeight, SuccessContainerAnimationSpec)
     }
     Box(
@@ -756,8 +769,10 @@
         }
     val failureContainerAnimationSpec: AnimationSpec<Float> =
         MaterialTheme.motionScheme.fastEffectsSpec()
+    val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
     LaunchedEffect(Unit) {
-        delay(DurationShort2.toLong())
+        animatedDelay(DurationShort2.toLong(), reduceMotionEnabled)
         shapeAnimatable.animateTo(1f, failureContainerAnimationSpec)
     }
 
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Dialog.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Dialog.kt
index c49273b..cd6b76d 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Dialog.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Dialog.kt
@@ -38,6 +38,7 @@
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.window.DialogProperties
 import androidx.compose.ui.window.DialogWindowProvider
+import androidx.wear.compose.foundation.LocalReduceMotion
 import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
 import androidx.wear.compose.material3.MotionScheme.Companion.standard
 import kotlinx.coroutines.flow.collectLatest
@@ -83,19 +84,23 @@
 
     val backgroundAnimationSpec = MaterialTheme.motionScheme.defaultEffectsSpec<Float>().faster(50f)
 
-    LaunchedEffect(Unit) {
-        snapshotFlow { showState }
-            .collectLatest {
-                if (it) {
-                    backgroundAnimatable.animateTo(0.85f, backgroundAnimationSpec) {
-                        scaffoldState.parentScale.floatValue = value
-                    }
-                } else {
-                    backgroundAnimatable.animateTo(1f, backgroundAnimationSpec) {
-                        scaffoldState.parentScale.floatValue = value
+    val isReduceMotionEnabled = LocalReduceMotion.current.enabled()
+
+    if (!isReduceMotionEnabled) {
+        LaunchedEffect(Unit) {
+            snapshotFlow { showState }
+                .collectLatest {
+                    if (it) {
+                        backgroundAnimatable.animateTo(0.85f, backgroundAnimationSpec) {
+                            scaffoldState.parentScale.floatValue = value
+                        }
+                    } else {
+                        backgroundAnimatable.animateTo(1f, backgroundAnimationSpec) {
+                            scaffoldState.parentScale.floatValue = value
+                        }
                     }
                 }
-            }
+        }
     }
 
     if (shouldShow) {
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/OpenOnPhoneDialog.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/OpenOnPhoneDialog.kt
index ea1cd22..6063174 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/OpenOnPhoneDialog.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/OpenOnPhoneDialog.kt
@@ -57,6 +57,7 @@
 import androidx.wear.compose.foundation.CurvedModifier
 import androidx.wear.compose.foundation.CurvedScope
 import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.LocalReduceMotion
 import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.material3.tokens.ColorSchemeKeyTokens
 import androidx.wear.compose.material3.tokens.MotionTokens.DurationLong2
@@ -135,22 +136,24 @@
         val progressDuration = a11yFullDurationMillis - finalAnimationDuration
 
         val alphaAnimationSpec = MaterialTheme.motionScheme.fastEffectsSpec<Float>()
+        val reduceMotionEnabled = LocalReduceMotion.current.enabled()
 
         LaunchedEffect(a11yFullDurationMillis) {
             launch {
-                delay(DurationShort3.toLong())
+                animatedDelay(DurationShort3.toLong(), reduceMotionEnabled)
                 alphaAnimatable.animateTo(1f, alphaAnimationSpec)
             }
             launch {
-                progressAnimatable.snapTo(0f)
-                progressAnimatable.animateTo(
-                    targetValue = 1f,
-                    animationSpec =
-                        tween(durationMillis = progressDuration.toInt(), easing = LinearEasing),
-                ) {
-                    progress = value
+                if (!reduceMotionEnabled) {
+                    progressAnimatable.animateTo(
+                        targetValue = 1f,
+                        animationSpec =
+                            tween(durationMillis = progressDuration.toInt(), easing = LinearEasing),
+                    ) {
+                        progress = value
+                    }
+                    finalAnimation = true
                 }
-                finalAnimation = true
             }
         }
 
@@ -217,8 +220,10 @@
         val animation =
             AnimatedImageVector.animatedVectorResource(R.drawable.wear_m3c_open_on_phone_animation)
         var atEnd by remember { mutableStateOf(false) }
+        val reduceMotionEnabled = LocalReduceMotion.current.enabled()
+
         LaunchedEffect(Unit) {
-            delay(IconDelay)
+            animatedDelay(IconDelay, reduceMotionEnabled)
             atEnd = true
         }
         Icon(